Django REST structure foreign keys and filtering

I have the following models in a django application:

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] 

And 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') 

as well as 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,) 

What I need, I want to get all Models produced by a particular marker. How can I get all models with a specific make foreign key using query parameters? And my second question is - can I filter the results using queryparams to get models with a specific engine capacity?

One comment: it would be ideal if I could query the results using something like this in url: /api/models/?make=ford , where make is the slug field in the Make model

+10
source share
4 answers

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) 

For more information check the docs .

You can also use filtering with QUERY_PARAMS, but IMHO looks better.

+7
source

You can specify filter_fields = ('make__slug', ) in your view set. Remember to also enable filter_backends = (DjangoFilterBackend, ) . You will also need to add the django-filter dependency.

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

Then you query like /api/models/?make__slug=ford . Pay attention to the double underscore.

Documentation

If you don't like the make__slug keyword of the make__slug keyword in the URL, then you can create a filter class:

 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',) 

and then

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

/api/models/?make=ford should work.

+19
source

What you need to do in your view is something like this: It's called "Lookups that bind relationships"

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

filtration of models with specific power of the engine is similar

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

If you want both filters to be combined, you can link them:

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

more examples can be found here creating django requests

+1
source

Details on @ Vladimir Prudnikov answer :

The situation has changed a bit in recent versions of django-filter. You probably want:

 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',) 

See https://django-filter.readthedocs.io/en/master/ref/filters.html#field-name and https://django-filter.readthedocs.io/en/master/ref/filters.html# to. -field name

0
source

Source: https://habr.com/ru/post/972570/


All Articles