可以通过django-filter URL解析器执行`in``lookup_type`吗?

Ros*_*ers 15 django-filter django-rest-framework

我正在使用带有django-rest-framework的django-filter,我正在尝试实例化一个过滤器,该过滤器接受用于过滤查询集的数字列表

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
Run Code Online (Sandbox Code Playgroud)

如果我传入逗号分隔的整数列表,则完全忽略过滤器.

如果我传入一个整数,它会通过django-filter进入django的表单验证器并抱怨:

'Decimal' object is not iterable
Run Code Online (Sandbox Code Playgroud)

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

Ros*_*ers 26

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

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
Run Code Online (Sandbox Code Playgroud)

使用如下:

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
Run Code Online (Sandbox Code Playgroud)

现在我的接口接受以逗号分隔的整数列表.

  • 如果它是一个公开的API,这看起来有点像安全问题.可以通过请求疯狂数量的ID来完成DOS吗? (2认同)

Die*_*sel 8

我知道这是一个老帖子,但现在有一个更好的解决方案.使其正确的更改将发布在此处.

他们增加了一个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']
Run Code Online (Sandbox Code Playgroud)


ynd*_*lok 6

这是一个完整的解决方案:

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
Run Code Online (Sandbox Code Playgroud)