I have following models in django app:
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')
and also 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 to to, I want to fetch all Models manufactured by specific make. How can I get all models with particular make foreign key using query params? And my 2nd question - can I filter results using queryparams to get models with specific engine_capacity?
One comment: It would be perfect, if I can to query results using something like this in url: /api/models/?make=ford
where make is slug
field in Make
model
Prerequisite: Adding Filtering in APIs – Django REST Framework [lin needed article on published yet] Django filters facilitate filtering the queryset to retrieve the relevant results based on the values assigned to the filter fields.
What is ForeignKey in Django? ForeignKey is a Field (which represents a column in a database table), and it’s used to create many-to-one relationships within tables. It’s a standard practice in relational databases to connect data using ForeignKeys. What’s the difference between foreign key and primary key?
This is nice, but it exposes the Django's double underscore convention as part of the API. If you instead want to explicitly name the filter argument you can instead explicitly include it on the FilterSet class:
The following third party packages provide additional filter implementations. The django-rest-framework-chain package works together with the DjangoFilterBackend class, and allows you to easily create filters across relationships, or create multiple filter lookup types for a given field.
You can specify filter_fields = ('make__slug', )
in your view set. Don't forget to include filter_backends = (DjangoFilterBackend, )
as well. Also you will need to add 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
. Note double underscore symbol.
Docs.
If you don't like make__slug
keyword argument 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(field_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.
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 info checkout the docs.
You can also use filtering with QUERY_PARAMS, but IMHO this looks better.
To expand on @vladimir-prudnikov's answer:
Things 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
What you need to do in your view is something like this: It is called "Lookups that span relationships"
queryset = Model.objects.filter(make__name__exact='Alfa Romeo')
the filtering of models with specific engine capacity is similar
queryset = Model.objects.filter(engine_capacity__exact=5)
if you want both filters combined, you can chain them:
queryset = Model.objects.filter(make__name__exact='Alfa Romeo').filter(engine_capacity__exact=5)
more examples can be found here django query making
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With