Django rest framework 是否可以通过django筛选器URL解析器执行'in``查找\u type`?

Django rest framework 是否可以通过django筛选器URL解析器执行'in``查找\u type`?,django-rest-framework,django-filter,Django Rest Framework,Django Filter,我正在使用with,并尝试实例化一个过滤器,该过滤器接受用于过滤查询集的数字列表 class MyFilter(django_filters.FilterSet): ids = django_filters.NumberFilter(name='id',lookup_type='in') class Meta: model = MyModel fields = ('ids',) class MyModelViewSet(viewsets.M

我正在使用with,并尝试实例化一个过滤器,该过滤器接受用于过滤查询集的数字列表

class MyFilter(django_filters.FilterSet):   
    ids = django_filters.NumberFilter(name='id',lookup_type='in')
    class Meta:
        model = MyModel
        fields = ('ids',)

class MyModelViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer
    filter_class = MyFilter
如果我传入一个逗号分隔的整数列表,过滤器将被完全忽略

如果我传入一个整数,它将通过django过滤器进入django的表单验证程序,并抱怨:

'Decimal' object is not iterable

有没有办法创建一个django filter对象,它可以处理整数列表并正确过滤查询集?

无论好坏,我为此创建了一个自定义筛选器:

class IntegerListFilter(django_filters.Filter):
    def filter(self,qs,value):
        if value not in (None,''):
            integers = [int(v) for v in value.split(',')]
            return qs.filter(**{'%s__%s'%(self.name, self.lookup_type):integers})
        return qs
它的用法如下:

class MyFilter(django_filters.FilterSet):   
    ids = IntegerListFilter(name='id',lookup_type='in')
    class Meta:
        model = MyModel
        fields = ('ids',)

class MyModelViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer
    filter_class = MyFilter

现在,我的接口接受逗号分隔的整数列表。

根据中的帖子:


我个人在我的项目中使用过它,没有任何问题,而且它不需要创建每种类型的过滤器即可工作。

以下是一个完整的解决方案:

from django_filters import Filter, FilterSet
from rest_framework.filters import DjangoFilterBackend
from rest_framework.viewsets import ModelViewSet
from .models import User
from .serializers import UserSerializer


class ListFilter(Filter):

    def filter(self, qs, value):
        if not value:
            return qs

        self.lookup_type = 'in'
        values = value.split(',')
        return super(ListFilter, self).filter(qs, values)


class UserFilter(FilterSet):
    ids = ListFilter(name='id')

    class Meta:
        model = User
        fields = ['ids']


class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    queryset = User.objects.all()
    filter_backends = (DjangoFilterBackend,)
    filter_class = UserFilter

基于@yndolok的回答,我得出了一个通用的解决方案。我认为通过ID列表进行过滤是一项非常常见的任务,因此应该包括在FilterBackend中:

类列表过滤器(django_filters.Filter):
“”“要从整数列表中筛选的类。”“”
def过滤器(自身、qs、值):
“”“筛选函数。”“”
如果不是值:
返回qs
self.lookup_type='in'
尝试:
映射(int,value.split(','))
返回super(ListFilter,self).filter(qs,value.split(','))
除值错误外:
返回超级(ListFilter,self).filter(qs,[None])
类FilterBackend(filters.DjangoFilterBackend):
“”“包含ListFilter的筛选器后端。”“”
def get_filter_类(self、view、queryset=None):
“”“将列表筛选器附加到自动筛选器集。”“”
filter\u fields=getattr(视图“filter\u fields”,无)
如果筛选字段:
类自动过滤器集(自身默认过滤器集):
ids=ListFilter(name='id')
类元:
model=queryset.model
字段=列表(筛选字段)+[“ID”]
返回自动过滤器集
其他:
返回super(FilterBackend,self).get\u filter\u类(view,queryset)

我知道这是一篇老文章,但现在有了更好的解决方案。使其正确的更改已发布

他们添加了一个
BaseInFilter
和一个
BaseRangeFilter
。文件是

大画面,BaseFilter检查CSV,然后当与另一个过滤器混合时,它会按您的要求执行。您的代码现在可以编写为:

class NumberInFilter(filters.BaseInFilter, filters.NumberFilter):
    pass

class MyModelViewSet(viewsets.ModelViewSet):
    ids = NumberInFilter(name='id', lookup_expr='in')

    class Meta:
        model = MyModel
        fields = ['ids']
最新解决方案:

from django_filters import Filter, FilterSet
from rest_framework.filters import DjangoFilterBackend
from rest_framework.viewsets import ModelViewSet
from .models import User
from .serializers import UserSerializer


class ListFilter(Filter):

    def filter(self, qs, value):
        if not value:
            return qs

        self.lookup_type = 'in'
        values = value.split(',')
        return super(ListFilter, self).filter(qs, values)


class UserFilter(FilterSet):
    ids = ListFilter(name='id')

    class Meta:
        model = User
        fields = ['ids']


class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    queryset = User.objects.all()
    filter_backends = (DjangoFilterBackend,)
    filter_class = UserFilter
从django_过滤器将rest_框架作为过滤器导入

名称-->字段名称

查找类型-->查找表达式

class IntegerListFilter(filters.Filter):
    def filter(self,qs,value):
        if value not in (None,''):
            integers = [int(v) for v in value.split(',')]
            return qs.filter(**{'%s__%s'%(self.field_name, self.lookup_expr):integers})
        return qs

class MyFilter(filters.FilterSet):   
    ids = IntegerListFilter(field_name='id',lookup_expr='in')
    class Meta:
        model = MyModel
        fields = ('ids',)

class MyModelViewSet(viewsets.ModelViewSet):
    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer
    filter_class = MyFilter
正如我在这里回答的,现在制作一个接受列表并验证内容的过滤器非常容易

例如:


从django_过滤器导入rest_框架作为过滤器
类别NumberFilter(filters.BaseFilter、filters.NumberFilter):
通过
类MyFilter(filters.FilterSet):
id\u in=NumberInFilter(字段\u name='id',lookup\u expr='in')
类元:
model=MyModel
字段=['id_in',]

这将接受get参数中的整数列表。例如,
/endpoint/?id\u in=1,2,3

好,我在视图中使用您的拆分方法将逗号分隔的请求id解析为来自django admin的导出对象id,如中所述,如果它是一个公开可用的API,这看起来有点像一个安全问题。可以通过请求数量惊人的ID来完成DOS吗?你是对的。您可以像
value[0:1000]那样截断值长度。拆分(“,”)
这以前对我有用,但现在它停止了,我不知道为什么。当我尝试这样做时,我现在得到了“int()参数必须是字符串或数字,而不是‘列表’”。我知道这是旧的,但现在有了一种受支持的方法,正如我在下面发布的那样。这个答案没有添加任何新的内容,只是通过@Diesel重复了以前的答案。确实,我一定错过了那个答案。