Django Rest Framework ManyToMany过滤多个值

时间:2016-09-07 11:15:07

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

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

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

到目前为止,我已经设法通过执行:/api/users/?labels=1查询具有给定标签的用户(让我们说id = 1),但我无法查询标签为1的用户2.我已尝试/api/users/?labels=1,2/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',)

3 个答案:

答案 0 :(得分:5)

您可以使用链式过滤器来解决问题 例如,如果您需要所有标签包含1 and 2值的用户,您可以像这样编写查询:

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

答案 1 :(得分:0)

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]

似乎有效!

答案 2 :(得分:0)

我有同样的问题,发现了以下内容:

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