在基于 Django 的 GraphQL API 中为 postgres 表创建全局搜索字段的最佳方法?
Posted
技术标签:
【中文标题】在基于 Django 的 GraphQL API 中为 postgres 表创建全局搜索字段的最佳方法?【英文标题】:Best approach to create a global search field for a postgres table in Django based GraphQL API? 【发布时间】:2021-08-13 19:14:57 【问题描述】:我正在使用带有 Django-graphene GraphQL API 和 postgres db 的 Angular UI。
目前,我已经实现了一个功能,通过为每个表添加一个“searchField”并在每次创建和更新该表中的项目时更新它来到达全局搜索字段。并且使用 graphql 过滤器,每次用户进行全局搜索时,我都会为查询过滤 hte searchField。我对 Django 很陌生,所以我不确定这是否是解决此问题的有效方法,但这就是我所拥有的:-
创建突变
class CreateUser(graphene.Mutation):
class Arguments:
input = UserInput(required=True)
ok = graphene.Boolean()
user = graphene.Field(UserType)
@staticmethod
def mutate(root, info, input=None):
ok = True
searchField = input.username if input.username is not None else "" + \
input.title if input.title is not None else "" + \
input.bio if input.bio is not None else ""
user_instance = User(user_id=input.user_id, title=input.title, bio=input.bio,
institution_id=input.institution_id, searchField=searchField)
user_instance.save()
return CreateUser(ok=ok, user=user_instance)
更新变异
class UpdateUser(graphene.Mutation):
class Arguments:
id = graphene.Int(required=True)
input = UserInput(required=True)
ok = graphene.Boolean()
user = graphene.Field(UserType)
@staticmethod
def mutate(root, info, id, input=None):
ok = False
user = User.objects.get(pk=id)
user_instance = user
if user_instance:
ok = True
user_instance.name = input.name if input.name is not None else user.name
user_instance.avatar = input.avatar if input.avatar is not None else user.avatar
user_instance.institution_id = input.institution_id if input.institution_id is not None else user.institution_id
user_instance.title = input.title if input.title is not None else user.title
user_instance.bio = input.bio if input.bio is not None else user.bio
user_instance.searchField = user_instance.searchField + \
user_instance.name if user_instance.name is not None else ""
user_instance.searchField = user_instance.searchField + \
user_instance.title if user_instance.title is not None else ""
user_instance.searchField = user_instance.searchField + \
user_instance.bio if user_instance.bio is not None else ""
user_instance.save()
return UpdateUser(ok=ok, user=user_instance)
return UpdateUser(ok=ok, user=None)
不确定你是否能说出来,但我对 Python 和 Django 很陌生。我在这里所做的是,每次创建或更新用户记录时,我都会在表中维护一个名为 searchField
的字段,该字段将包含表中我希望全局搜索的所有字段的字符串涉及。我已经像这样手动编写了每一行。不确定这是否符合最佳做法。
这是用户模型。
用户模型
class User(AbstractUser):
name = models.CharField(max_length=50)
email = models.EmailField(blank=False, max_length=255, unique=True)
avatar = models.CharField(max_length=250, blank=True, null=True)
institution = models.ForeignKey(
'Institution', on_delete=models.PROTECT, blank=True, null=True)
title = models.CharField(max_length=150, blank=True, null=True)
bio = models.CharField(max_length=300, blank=True, null=True)
searchField = models.CharField(max_length=600, blank=True, null=True)
USERNAME_FIELD = 'username'
EMAIL_FIELD = 'email'
所以这里有几件事。
-
首先,我知道我在设置更新突变解析器方法中的 searchField 更新方面做错了。那是由于我对Python的了解不足。因此,如果有人能弄清楚我做错了什么,那就太好了。
我完全是在自己做这件事,我不知道这种方法在效率方面是否真的是一个好的策略,或者是否已经有一个基于 graphql 的 django api 的好的解决方案。所以如果有请指点我。
谢谢。
【问题讨论】:
【参考方案1】:是的,如果您想更新您的 searchField,您必须从头开始构建它。如果您使用旧数据并附加新数据,如果您搜索旧数据,它将返回记录,这是您要避免的。
关于第二个问题,您可以使用django-filter
。
步骤:
安装django-filter
创建一个基本过滤器集类并向其添加search
字段
class CustomFilterSet(filters.FilterSet):
search = filters.CharFilter(method='search_filter')
def search_filter(self, queryset, field_name, value):
return queryset
为继承自自定义过滤器集类的模型创建过滤器集类并覆盖search_filter
方法。为了对查询集执行or
操作,请使用Q
对象。在你的情况下是这样的:
class UserFilterSet(CustomFilterSet):
...
def search_filter(self, queryset, field_name, value):
return queryset.filter(
Q(username__icontains=value) |
Q(title__icontains=vallue) |
Q(bio__icontains=value)
)
在指定字段中查找值,而不管 小写/大写
创建graphql类型并将相关的filterset_class添加到Meta类:
class UserType(DjangoObjectType):
class Meta:
model = User
filterset_class = UserFilterSet
interfaces = (relay.Node, )
现在您可以通过仅传递一个字符串来全局搜索指定的字段。
【讨论】:
以上是关于在基于 Django 的 GraphQL API 中为 postgres 表创建全局搜索字段的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章
GraphQL graphene-django 基本使用文档
当我使用 Graphene 在 Django GraphQL API 中获取对象时,如何限制 ForeignKey 字段的项目数?