微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在基于 Django 的 GraphQL API 中为 postgres 表创建全局搜索字段的最佳方法?

如何解决在基于 Django 的 GraphQL API 中为 postgres 表创建全局搜索字段的最佳方法?

我正在使用带有 Django-graphene GraphQL API 和 postgres 数据库的 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,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,null=True)
    title = models.CharField(max_length=150,null=True)
    bio = models.CharField(max_length=300,null=True)
    searchField = models.CharField(max_length=600,null=True)
    USERNAME_FIELD = 'username'
    EMAIL_FIELD = 'email'

这里有几件事。

  1. 首先,我知道我在更新突变解析器方法中设置 searchField 的更新方面做错了。这是由于我对 Python 的了解不足。因此,如果有人能找出我做错了什么,那就太好了。
  2. 我完全自己做这件事,我不知道这种方法在效率方面是否真的是一个很好的策略,或者是否已经有一个基于 graphql 的 django api 的好的解决方案。所以如果有的话,请指点我。

谢谢。

解决方法

是的,如果您想更新您的 searchField,您必须从头开始构建它。如果您使用旧数据并附加新数据,如果您搜索旧数据,它将返回记录,这是您想要避免的。

关于您的第二个问题,您可以使用 django-filter

步骤:

  1. 安装django-filter

  2. 创建一个基本过滤器集类并向其添加 search 字段

    class CustomFilterSet(filters.FilterSet):
        search = filters.CharFilter(method='search_filter')
    
        def search_filter(self,queryset,field_name,value):
            return queryset
    
  3. 为从自定义过滤器集类继承的模型创建过滤器集类并覆盖 search_filter 方法。为了对查询集执行 or 操作,请使用 Q 对象。在你的情况下是这样的:

    class UserFilterSet(CustomFilterSet):
        ...
        def search_filter(self,value):
            return queryset.filter(
                Q(username__icontains=value) |
                Q(title__icontains=vallue) |
                Q(bio__icontains=value)
            )
    

    查找指定字段中的值,而不管 小写/大写

  4. 创建 graphql 类型并将相关的 filterset_class 添加到 Meta 类:

    class UserType(DjangoObjectType):
        class Meta:
            model = User
            filterset_class = UserFilterSet
            interfaces = (relay.Node,)
    

现在您只需传递一个字符串即可全局搜索指定字段。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。