Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework - filter many-to-many field

Suppose I have a model like this one:

class Car(models.Model):
    images = models.ManyToManyField(Image)

class Image(models.Model):
    path = models.CharField()
    type = models.CharField()

I want to expose two API views:

  • cars list
  • car details

In list view I want to show only images that have type="thumbnail". In details view I want to show images of type="image".

This is more or less what the list should look like:

[{
    "id": 1,
    "images": [1, 2],
},
{
    "id": 2,
    "images": [3, 4],
}]

And the details view:

{
    "id": 1,
    "images": [5],
}

Note that different image ids are displayed depending on the view.

So far my serializer looks like this:

class CarSerializer(serializers.ModelSerializer):
    images = serializers.ManyPrimaryKeyRelatedField()

    class Meta:
        model = Car

List api view:

class CarList(generics.ListAPIView):
    model = Car
    serializer_class = CarSerializer

Details api view:

class CarDetails(generics.RetrieveAPIView):
    model = Car
    serializer_class = CarSerializer

This of course gives me all images in list as well as in details and forces clients to make additional calls to get image type that should be displayed.

Is there any generic way to do it? I have seen django-filter examples, but it seems that its only possible to filter which objects are listed, not what related objects in listed objects are listed.

like image 366
Jacek Chmielewski Avatar asked Feb 07 '13 11:02

Jacek Chmielewski


People also ask

What is Queryset in Django REST framework?

The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects. The default behavior of REST framework's generic list views is to return the entire queryset for a model manager.

What is Query_params in Django?

query_params is a more correctly named synonym for request. GET . For clarity inside your code, we recommend using request. query_params instead of the Django's standard request.


2 Answers

I don´t know if you are still looking for this answer, but maybe it helps someone else.

First create a filter class like this:

class CarFilter(django_filters.FilterSet):
    having_image = django_filters.Filter(name="images", lookup_type='in')

    class Meta:
        model = Car

Then add the filter to your view:

class CarList(generics.ListAPIView):
    model = Car
    serializer_class = CarSerializer
    filter_class = CarFilter

And that´s all. Add "?having_image=1" to your query string and Django filter should do the trick for you.

Hope it helps..

like image 95
Fábio Gibson Avatar answered Oct 09 '22 07:10

Fábio Gibson


I have found a other Stackoverflow question that has a solution that could be used here:

How can I apply a filter to a nested resource in Django REST framework?

(see under the "Solution" headline in the question itself)

like image 41
Anton Avatar answered Oct 09 '22 08:10

Anton