django-filter + DRF ModelView为不同的字段设置不同的行为

Posted

技术标签:

【中文标题】django-filter + DRF ModelView为不同的字段设置不同的行为【英文标题】:django-filter + DRF ModelViewSet different behaviour for different fields 【发布时间】:2021-10-28 08:52:23 【问题描述】:

我有以下 ViewSets(我当前的代码)

class TeacherViewSet(viewsets.ModelViewSet):
    queryset = Teacher.objects.all()
    serializer_class = TeacherSerializer
    filter_backends = [DjangoFilterBackend, SearchFilter]
    filterset_fields = ['user_id', ]
    search_fields = ['=user_id']


class SchoolViewSet(viewsets.ModelViewSet):
    queryset = School.objects.filter()
    serializer_class = SchoolSerializer
    filter_backends = [filters.SearchFilter]
    filterset_fields = ['udise', ]
    search_fields = ['=udise']

模型看起来像这样

class Teacher(BaseModel):
    school = models.ForeignKey(School, on_delete=models.SET_NULL, null=True)
    user_id = models.UUIDField()


class School(models.Model):
    id = models.AutoField(primary_key=True)
    udise = models.IntegerField(unique=True)

School 的序列化器如下

class SchoolSerializer(serializers.ModelSerializer):

    class Meta:
        model = School
        fields = '__all__'
        validators = []

如果我把它改成这个(我认为它应该像TeacherSet一样工作

class SchoolViewSet(viewsets.ModelViewSet):
    queryset = School.objects.filter()
    serializer_class = SchoolSerializer
    filter_backends = [DjangoFilterBackend, SearchFilter]
    filterset_fields = ['udise', ]
    search_fields = ['=udise']

我面临的问题是

/school/?udise=111 不起作用,也不过滤任何东西 /teacher/?user_id=4a031bd9-4c02-4f9a-8c1b-56fb68965021 工作得很好。

我想我在这里遗漏了一些非常基本的东西。 user_idudise 在数据库中都是唯一的。 因此,为了缓解这种情况,我目前在 DRF 的默认 SearchFilter 后端使用 hack - search_fields=

【问题讨论】:

您从哪里导入SearchFilter 中的SchoolViewset?我的意思是,在TeacherViewSet 中您直接使用它,而在第二个视图集中您通过filters.SearchFilter 访问它 @Ersain 当我将SchoolViewSet 中的filters.SearchFilter 替换为DjangoFilterBackend 时,它会返回阳光下的所有内容。不知道为什么会这样。这些是我的进口商品from rest_framework import filters; from django_filters.rest_framework import DjangoFilterBackend 【参考方案1】:

/school/?udise=111/teacher/?user_id=4a031bd9-4c02-4f9a-8c1b-56fb68965021 中,您尝试的是过滤,而不是搜索。

搜索 url 会像:/?search=sth。然后它在search_fields 中的指定字段中搜索,并尝试找到与这些字段匹配的对象。这些字段应该是能够搜索的文本类型。请参阅有关搜索的文档:https://www.django-rest-framework.org/api-guide/filtering/#searchfilter

但是在这里,您正在尝试过滤,因此您应该使用DjangoFilterBackend 或自定义过滤器进行过滤:

class SchoolViewSet(viewsets.ModelViewSet):
    ...
    filter_backends = [DjangoFilterBackend]

【讨论】:

当我将 SchoolViewSet 中的 filters.SearchFilter 替换为 DjangoFilterBackend 时,它不会过滤任何内容。 为清晰起见已更新

以上是关于django-filter + DRF ModelView为不同的字段设置不同的行为的主要内容,如果未能解决你的问题,请参考以下文章

Django(69)最好用的过滤器插件Django-filter

drf 过滤器组件与自定义过滤器

DRF的过滤与排序

Python后台开发偷懒神器Django-Filter介绍与刁钻需求的实现方法

Django-Filter源码解析一

如何使用 Django-filter 过滤多个字段?