【问题标题】:Django REST Framework ManyToMany filter multiple valuesDjango REST Framework ManyToMany 过滤多个值
【发布时间】:2017-01-15 01:21:39
【问题描述】:

我有两个模型,一个定义用户,另一个定义这些用户的标签。我正在使用 Django REST Framework 来创建 API。我希望能够查询至少包含标签 id 1 和 2 的用户。

例如,如果用户的标签是: [(1,2), (1,2,3), (2,3), (1,3)]我要查询返回 [(1,2), (1,2,3)].

到目前为止,我已经设法通过以下方式查询具有给定标签(假设 id=1)的用户:/api/users/?labels=1,但我无法查询具有标签 1 和 2 的用户。我尝试过 @987654325 @ 或 /api/users/?labels=1&labels=2 但它返回一些无效用户,即没有标签 1 或 2 的用户...

Github 测试仓库:

https://github.com/TheDimLebowski/drf-m2m-filter

代码:

models.py

​​>
class Label(models.Model):
    name = models.CharField(max_length = 60)

class User(models.Model):
    labels = models.ManyToManyField(Label)

filters.py

​​>
class UserFilter(django_filters.FilterSet):
    labels = django_filters.filters.BaseInFilter(
        name='labels',
        lookup_type='in',
    )

    class Meta:
        model = User
        fields = ('labels',)

serializers.py

​​>
class LabelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Label
        fields = ('id','name')

class UserSerializer(serializers.ModelSerializer):
    labels = LabelSerializer(many = True)
    class Meta:
        model = User
        fields = ('labels',)

views.py

​​>
class UserViewSet(viewsets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = UserFilter
    filter_fields = ('labels',)

【问题讨论】:

    标签: django many-to-many django-rest-framework


    【解决方案1】:

    您可以链接过滤器。例如,如果您需要标签同时包含 12 值的所有用户,您可以编写如下查询:

    User.objects.filter(labels=1).filter(labels=2)
    

    django-filters 默认不支持这样的查询,所以你需要一个自定义过滤器。

    class M2MFilter(django_filters.Filter):
    
        def filter(self, qs, value):
            if not value:
                return qs
        
            values = value.split(',')
            for v in values:
                qs = qs.filter(labels=v)
            return qs
    
    
    class UserFilter(django_filters.FilterSet):
        labels = M2MFilter(name='labels')
    
        class Meta:
            model = User
            fields = ('labels',)
    

    现在您可以编写标签 id 的逗号分隔并得到您所需要的内容

    /api/users/?labels=1,2
    

    Here is good answer about m2m queries

    【讨论】:

    • 非常感谢您的回答。恐怕它会导致同样的问题......所有这些符号:?labels=1&labels=2 ?labels=1,2?labels=1&2
    • @TheDimLebowski 它将返回带有标签676 and 7 的用户。
    • 我们可以限制标签1 and 2吗?
    • @TheDimLebowski 不是6 and 7 而是1 and 2 我想说。您想限制基本查询集吗?所以你可以在现场进行,只需按 id 过滤,ModelMultipleChoiceFilter(queryset=Label.objects.filter(pk__in=[1,2])) 现在它将按 121 and 2 过滤
    • 让我澄清一下。我希望基本查询集是所有用户。现在通过查询?labels=1&2 我想要一个带有标签1 and 2 的用户列表。
    【解决方案2】:

    UserViewSet 中使用链接过滤器如下:

    class UserViewSet(viewsets.ModelViewSet):
        queryset = User.objects.all()
        serializer_class = UserSerializer
        filter_backends = (filters.DjangoFilterBackend,)
        def get_queryset(self):
            queryset = User.objects.all()
            labels = eval(self.request.query_params.get('labels', []))
            for label in labels:
                queryset = queryset.filter(labels__in=[label])
            return queryset
    

    查询如下:

    /api/users/?labels=[1,2]
    

    似乎有效!

    【讨论】:

      【解决方案3】:

      我有同样的问题,我发现了这样的事情:

      from django.db.models import Q
      from rest_framework import viewsets
      
      class YourViewSet(viewsets.ModelViewSet)
      
          def get_queryset(self):
              # get lable infos here
              lables_info = self.request.query_params.get('lable')
              lables = lables_info.split(',')
              lable1, lable2 = lables[0], lables[1]
      
              return models.objects.fliter(
                  Q(lable=lable1) | Q(lable=lable2)
              )
      .......
      

      Django==2.2.4

      djangorestframework==3.10.2

      django-filter==2.2.0

      【讨论】:

        猜你喜欢
        • 2021-03-09
        • 2018-10-03
        • 1970-01-01
        • 2014-02-03
        • 1970-01-01
        • 2018-08-07
        • 1970-01-01
        • 1970-01-01
        • 2015-09-21
        相关资源
        最近更新 更多