【问题标题】:Django-Filter and query with an arrayDjango-过滤和查询数组
【发布时间】:2015-09-22 12:17:25
【问题描述】:

我有一个简单的问题:目前我可以这样做以从后端获取对象:

http://127.0.0.1:8000/api/v1/boats/boats?id=10
http://127.0.0.1:8000/api/v1/boats/boats?home_port=98&id=5

但我想根据 id 列表或 home_ports 列表获取一组船,我已经尝试过:

http://127.0.0.1:8000/api/v1/boats/boats?id=10,11
http://127.0.0.1:8000/api/v1/boats/boats?id_in=10,11
http://127.0.0.1:8000/api/v1/boats/boats?id=10,id=11
http://127.0.0.1:8000/api/v1/boats/boats?id=10&id=11

但是这些不起作用。使用 django-filter 执行此操作的最佳方法是什么,URL 规则是如何定义的?

这是我的看法:

class BoatList(generics.ListCreateAPIView):
    permission_classes = (IsOwnerOrReadOnly,)
    serializer_class = BoatSerializer
    queryset = Boat.objects.all()
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('id', 'home_port',)

我标记为接受的解决方案 100% 回答了我的问题,但我最终根据我发现的另一个使用过滤器的帖子实施了一些不同的解决方案:

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 BoatFilter(FilterSet):
    ids = ListFilter(name='id')

    class Meta:
        model = Boat
        fields = ['home_port', 'ids']


class BoatList(generics.ListCreateAPIView):
    permission_classes = (IsOwnerOrReadOnly,)
    serializer_class = BoatSerializer
    queryset = Boat.objects.all()
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = BoatFilter

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

【问题讨论】:

    标签: python django api django-rest-framework django-filter


    【解决方案1】:

    doniyor给出的答案非常贴切。但我猜request 在使用它的地方将不可用。

    还有另一种方法。您可以覆盖get_queryset 方法。这可以按如下方式完成:

    class BoatList(generics.ListCreateAPIView):
        permission_classes = (IsOwnerOrReadOnly,)
        serializer_class = BoatSerializer
        filter_backends = (filters.DjangoFilterBackend,)
        filter_fields = ('id', 'home_port',)
    
        def get_queryset(self):
            id_list = self.request.GET.getlist("id")
            if not id_list:
                return []
            return Boat.objects.filter(id__in=id_list)
    

    【讨论】:

    • 上面的一个小问题是,如果 id 不存在,getlist("id") 将返回一个空列表,然后它将过滤空列表中的成员资格。
    • @MarkGalloway 感谢您指出这一点。更正了代码。
    • 感谢您的支持,以及多尼奥的评论。那么有没有办法用过滤器做到这一点?必须用实际的查询集本身来完成吗?无论如何,测试了这个,它可以工作!为了使它工作,一个小的更改 id_list = self.request.GET.getlist("id")[0].split(',') 因为它返回了一个包含值 '10,11' 的元素的数组。再次感谢!
    【解决方案2】:

    试试这个:

    网址:http://127.0.0.1:8000/api/v1/boats/boats?id=10,11

    class BoatList(generics.ListCreateAPIView):
        permission_classes = (IsOwnerOrReadOnly,)
        serializer_class = BoatSerializer
        queryset = Boat.objects.filter(id__in=request.GET.getlist('id')) #<------
        filter_backends = (filters.DjangoFilterBackend,)
        filter_fields = ('id', 'home_port',)
    

    【讨论】:

      【解决方案3】:

      你只需创建一个过滤器类

          class NumberInFilter(BaseInFilter, NumberFilter):
                pass
      
      
          class myFilter(FilterSet):
                id__in = NumberInFilter(field_name='id', lookup_expr='in')
      
                class Meta:
                      model = Boat
      

      在视图集中使用

                 filter_class = myFilter
      

      你可以看到这个 django-filter 的文档: https://django-filter.readthedocs.io/en/master/ref/filters.html?highlight=BaseInFilter

      【讨论】:

      • 我推荐这个,Django 也推荐这个
      • 这是用数组查询的正确方法。谢谢。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-04
      • 1970-01-01
      • 2020-08-22
      • 2019-04-15
      相关资源
      最近更新 更多