drf使用mongodb时实现过滤搜索,通过字典拆包解包实现将变量作为关键字参数的key

最近公司要记录用户行为记录日志用到了mongodb,项目框架用的是django rest framework, 用mongodb作为用户行为日志记录数据库导致了django-filter的过滤和drf的search功能都无法使用。网上没能查到解决方法,只能自己写一个过滤和搜索了。

下面展示一些 过滤搜索代码,主要是过滤start_time和end_time字段,并对title, user等字段进行搜索。
class BehaviorLogView(generics.ListAPIView):
    """用户行为记录"""
    # permission_classes = ["IsAdmin"]
    serializer_class = BehaviorLogTSerializer
    filter_backends = (OrderingFilter, )
    ordering = ("-update_time",)
    search_fields = ("user", "module", "title")

    def get_queryset(self):
        # self.filter_queryset()
        return UserBehavior.objects.all()

    def filter_queryset(self, queryset):
        params = self.request.query_params
        start_time = params.get("start_time")
        end_time = params.get("end_time")
        search = params.get("search")
        if start_time and is_valid_date(start_time):
            queryset = queryset.filter(create_time__gte=start_time)
        if end_time and is_valid_date(end_time):
            end_time = end_time + timedelta(days=1)
            queryset = queryset.filter(create_time__lt=end_time)
            
        # 主要看这里(通过Q方法的拼接方法将search_fields总的字段用or逻辑查询是否包含搜索的内容)
        if search:
            q1 = Q()
			q1.connector = 'OR'
            for field in self.search_fields:
                q1.children.append((field, search))
            queryset = queryset.filter(q)
            LOGGING.info(q)
        return queryset


    def get(self, request, *args, **kwargs):
        res = self.list(request, *args, **kwargs)
        return Response(data={'code': 200, 'msg': 'ok,获取成功!', 'data': res.data})
结果报一下错误: mongoengine.errors.InvalidQueryError: Not a query object:XXXXXXXXXXXXX
猜想是mongoengine中Q函数的使用跟django内置的Q函数有差异导致出错,于是使用mongoengine的Q函数重写
代码
from mongoengine import Q
# from django.db.models import Q

   def filter_queryset(self, queryset):
       params = self.request.query_params
       start_time = params.get("start_time")
       end_time = params.get("end_time")
       search = params.get("search")
       if start_time and is_valid_date(start_time):
           queryset = queryset.filter(create_time__gte=start_time)
       if end_time and is_valid_date(end_time):
           end_time = end_time + timedelta(days=1)
           queryset = queryset.filter(create_time__lt=end_time)
       # mongoengine中的Q方法无法使用上面的拼接方法,只能自己拼接
       if search:
           q = Q()
           for field in self.search_fields:
               q = q | Q(field=search)
           queryset = queryset.filter(q)
           LOGGING.info(q)
       return queryset
大家发现问题没有,上面这句代码q = q | Q(field=search)中python把field当成关键字参数的键了,我们想
实现的应该是q = q | Q(user=search),q = q | Q(module=search),q = q | Q(title=search),这个
问题比较抽象,不好表达。所以网上也找不到解决办法。最后我想起了字典的拆包解包运算符 "**",完美解决
// An highlighted block
    def filter_queryset(self, queryset):
        params = self.request.query_params
        start_time = params.get("start_time")
        end_time = params.get("end_time")
        search = params.get("search")
        if start_time and is_valid_date(start_time):
            queryset = queryset.filter(create_time__gte=start_time)
        if end_time and is_valid_date(end_time):
            end_time = end_time + timedelta(days=1)
            queryset = queryset.filter(create_time__lt=end_time)
        # 通过先封装成一个字典再用**运算符解包,完美解决
        if search:
            q = Q()
            for field in self.search_fields:
                zip_field = {field+'__icontains': search}
                q = q | Q(**zip_field)
            queryset = queryset.filter(q)
            LOGGING.info(q)
        return queryset
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值