簡體   English   中英

根據查詢參數過濾Django REST Framework,多對多

[英]Filtering against query parameters Django REST Framework, Many to Many

我正在嘗試構建某種API,但是我需要根據URL中的查詢參數過濾請求(http:// ... /?arg1 = foo1&arg2 = foo2&...)。 在我的模型方案中,我使用了許多關系。 這是我的一些代碼:


my_app應用/ models.py

from django.contrib.postgres.fields import JSONField
from django.db import models


class MyData(models.Model):
    name = models.CharField(max_length=20)
    values = JSONField()


class MyModel(models.Model):
    time = models.DateTimeField()
    country = models.CharField(max_length=50)
    data = models.ManyToManyField(MyData)

my_app應用/ serializers.py

from rest_framework import serializers
from my_app.models import MyModel, MyData


class MyDataSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyData
        fields = ('name', 'values',)


class MyModelSerializer(serializers.ModelSerializer):
    data = MyDataSerializer(many=True, read_only=True)

    class Meta:
        model = MyModel
        fields = ('country', 'data',)

my_app應用/ views.py

from rest_framework import generics
from my_app.serializers import MySerializer
from my_app.models import MyModel


class MyView(generics.ListAPIView):
    serializer_class = MySerializer

    def get_queryset(self):
        queryset = MyModel.objects.all()
        names = self.request.query_params.get('Simon', None)
        if names:
            queryset = queryset.filter(data__name__in=names.split(','))
        return queryset

這是回應


回應http://127.0.0.1:8000/hello/

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "country": "Spain",
        "data": [
            {
                "name": "Mark",
                "values": {"A": "Hello, it's Wario"}
            },
            {
                "name": "Simon",
                "values": {"A": "Hello, it's Mario"}
            },
        ]
    },

    {
        "country": "Italy",
        "data": [
            {
                "name": "Jake",
                "values": {"A": "Hello, it's Luigi"}
            }
        ]
    }
]

回應http://127.0.0.1:8000/hello/?name=Simon

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "country": "Spain",
        "data": [
            {
                "name": "Mark",
                "values": {"A": "Hello, it's Wario"}
            },
            {
                "name": "Simon",
                "values": {"A": "Hello, it's Mario"}
            },
        ]
    }
]

但是當我請求?name = Simon時,我想獲得的響應是​​:


回應http://127.0.0.1:8000/hello/?name=Simon

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
    {
        "country": "Spain",
        "data": [
            {
                "name": "Simon",
                "values": {"A": "Hello, it's Mario"}
            }
        ]
    }
]

嘗試使用prefetch_related過濾相關數據:

from django.db.models import Prefetch

class MyView(generics.ListAPIView):
    serializer_class = MySerializer

    def get_queryset(self):
        queryset = MyModel.objects.all()
        names = self.request.query_params.get('Simon', None)
        if names:
            queryset = queryset.filter(data__name__in=names.split(',')).prefetch_related(Prefetch('data', queryset=MyData.objects.filter(name__in=names.split(',')))
        return queryset

你也可以使用SerializerMethodField

class MyModelSerializer(serializers.ModelSerializer):
    data = SerializerMethodField()

    class Meta:
        model = MyModel
        fields = ('country', 'data',)

    def get_data(self, obj):
        names = self.context['request'].query_params.get('Simon', None)
        data = MyData.objects.filter(name__in=names.split(','))
        data_serializer = MyDataSerializer(data, many=True)
        return data_serializer.data

我認為我們可以使用Django Filter包來做到這一點。 要使用此軟件包,您需要將其安裝為其他任何python軟件包。 pip install django-filter將為您做同樣的事情。 然后,您需要在項目的任何位置定義一個自定義過濾器類,如下所示,

from django_filters import rest_framework as filters
from my_app.models import MyModel

class MyFilter(filters.FilterSet):
    name = filters.CharFilter(name='data__name')

    class Meta:
        model = MyModel
        fields = ['name', ]

然后,您必須按如下所示稍微更改views.py

from django_filters import rest_framework as filters


class MyView(generics.ListAPIView):
    serializer_class = MyModelSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = MyFilter

    def get_queryset(self):
        return MyModel.objects.all()



注意:我認為您可以使用此很棒的包定義和使用任何類型的過濾器,我可以自定義filter class

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM