Внешние ключи структуры Django REST и фильтрация

У меня есть следующие модели в приложении django:

models.py

class Make(BaseModel):
    slug = models.CharField(max_length=32) #alfa-romeo
    name = models.CharField(max_length=32) #Alfa Romeo

    def __unicode__(self):
        return self.name

class Model(BaseModel):
    make = models.ForeignKey(Make)  #Alfa Romeo
    name = models.CharField(max_length=64) # line[2]
    engine_capacity = models.IntegerField()
    trim = models.CharField(max_length=128) # line[4]

И serializers.py:

from .models import Make,Model
from rest_framework import serializers


class MakeSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Make
        fields = ('url', 'slug', 'name')


class ModelSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Model
        fields = ('url', 'make', 'name', 'trim', 'engine_capacity')

а также views.py:

from rest_framework import viewsets
from rest_framework import filters
from rest_framework import generics

from .models import Make, Model
from .serializers import MakeSerializer, ModelSerializer


class MakeViewSet(viewsets.ModelViewSet):
    queryset = Make.objects.all()
    serializer_class = MakeSerializer
    filter_backends = (filters.DjangoFilterBackend,)

class ModelViewSet(viewsets.ModelViewSet):
    make = MakeSerializer
    queryset = Model.objects.all()
    serializer_class = ModelSerializer
    filter_backends = (filters.DjangoFilterBackend,)

Что мне нужно, я хочу получить все Модели, произведенные конкретным маркером. Как я могу получить все модели с конкретным make foreign ключом с использованием параметров запроса? И мой второй вопрос - могу ли я фильтровать результаты с помощью queryparams для получения моделей с определенной машинной емкостью?

Один комментарий: было бы идеально, если бы я мог запросить результаты, используя что-то вроде этого в url: /api/models/?make=ford, где make - это slug поле в Make model

Ответ 1

urls.py

url('^model/by/(?P<make>\w+)/$', ModelByMakerList.as_view()),

views.py

class ModelByMakerList(generics.ListAPIView):
    serializer_class = ModelSerializer

    def get_queryset(self):
        """
        This view should return a list of all models by
        the maker passed in the URL
        """
        maker = self.kwargs['make']
        return Model.objects.filter(make=maker)

Для получения дополнительной информации проверить документы.

Вы также можете использовать фильтрацию с QUERY_PARAMS, но IMHO выглядит лучше.

Ответ 2

Вы можете указать filter_fields = ('make__slug', ) в вашем наборе представлений. Не забудьте также включить filter_backends = (DjangoFilterBackend, ). Также вам нужно будет добавить зависимость django-filter.

class ModelViewSet(viewsets.ModelViewSet):
    queryset = Model.objects.all()
    serializer_class = ModelSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('make__slug',)

Затем вы запрашиваете как /api/models/?make__slug=ford. Обратите внимание на символ двойного подчеркивания.

Документы

Если вам не нравится make__slug ключевого слова make__slug в URL, то вы можете создать класс фильтра:

import django_filters

from myapp.models import Make


class ModelFilter(django_filters.FilterSet):
    make = django_filters.ModelChoiceFilter(name="make__slug",
                                            queryset=Make.objects.all())

    class Meta:
        model = Model
        fields = ('make',)

а потом

class ModelViewSet(viewsets.ModelViewSet):
    make = MakeSerializer
    queryset = Model.objects.all()
    serializer_class = ModelSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_class = ModelFilter

/api/models/?make=ford должен работать.

Ответ 3

Что вам нужно сделать в вашем представлении, это примерно так: Он называется "Lookups, которые связывают отношения"

queryset = Model.objects.filter(make__name__exact='Alfa Romeo')

фильтрация моделей с удельной мощностью двигателя аналогична

queryset = Model.objects.filter(engine_capacity__exact=5)

Если вы хотите, чтобы оба фильтра были объединены, вы можете их связать:

queryset = Model.objects.filter(make__name__exact='Alfa Romeo').filter(engine_capacity__exact=5)

больше примеров можно найти здесь создание django-запросов

Ответ 4

Подробно на @владимир-прудников отвечу:

Ситуация немного изменилась в последних версиях django-filter. Вы, вероятно, хотите:

class ModelFilter(django_filters.FilterSet):
    make = django_filters.ModelChoiceFilter(field_name='make__slug',
                                            to_field_name='slug',
                                            queryset=Make.objects.all())

    class Meta:
        model = Model
        fields = ('make',)

См. Https://django-filter.readthedocs.io/en/master/ref/filters.html#field-name и https://django-filter.readthedocs.io/en/master/ref/filters.html#to. -field имя