对于跨越多值关系的查询,django-filter FilterSet行为是否与本机Django行为一致?

问题描述

我正在尝试通过收件人模型查询用户的所有未读邮件(即每封邮件有许多具有read属性的收件人)。与模型管理器一起运行时,查询按预期方式工作。例如:

Message.objects.filter(**{"recipients__user_id": 1,"recipients__read": False })

但是,查询包括用户在使用FilterSet(使用django-filter版本2.3.0)运行时收到的所有消息,无论读取状态如何。例如:

MessageFilter(data={"recipients__user_id": "1","recipients___read": False }).qs

这是MessageFilter:

class MessageFilter(FilterSet):
    class Meta:
        model = Message
        exclude = ('deleted_at',)
        fields = ('chat_id','recipients__user_id','recipients__read',)
        filter_overrides = {
          # NOTE: enables support for querying pk rather than relay uuid
          models.ForeignKey: { 'filter_class': LocalIDFilter },}

    # NOTE: enables mapping from camelcase to snakecase
    order_by = OrderingFilter(fields=(('created_at','createdAt'),),)

有人知道我的实现是否不正确,或者这仅仅是所需的库行为(我无法从文档中得知)吗?此外,任何建议的解决方法将不胜感激。除了手动覆盖FilterSet的qs属性外,我看不到任何更好的解决方案。

解决方法

我一直在研究源代码,并且看来库的实现是不一致的(尽管这可能是有意的设计决策)。但是,我可以通过以下内容覆盖filter_queryset方法来实现所需的过滤器:

class MessageFilter(FilterSet):
    
    ...
    
    def filter_queryset(self,queryset):
        queryset = queryset.filter(**{k: v for k,v in self.form.cleaned_data.items() if v is not None})
        assert isinstance(queryset,models.QuerySet),\
            "Expected '%s.%s' to return a QuerySet,but got a %s instead." \
            % (type(self).__name__,name,type(queryset).__name__)

        # NOTE: native implementation
        # for name,value in self.form.cleaned_data.items():
        #     queryset = self.filters[name].filter(queryset,value)
        #     assert isinstance(queryset,\
        #         "Expected '%s.%s' to return a QuerySet,but got a %s instead." \
        #         % (type(self).__name__,type(queryset).__name__)
        
        return queryset