Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework (GET filter on ManyToMany field)

I am trying to figure out how to filter a ManyToMany field by value. In Django, it is as simple as queryset.filter(m2mfield__name), but I can't quite figure out what I am missing. I am using the Django Rest Framework, and the DjangoFilterBackend.

Models:

class City(models.Model):
    name = models.CharField(max_length=80)

class State(models.Model):
    name = models.CharField(max_length=50)
    cities = models.ManyToManyField(City)

Filters:

import django_filters

class StateFilter(django_filters.FilterSet):
    cities = django_filters.CharFilter(
        name='cities__name',
        lookup_type='contains',
    )

    class Meta:
        model = State
        fields = ('name', 'cities')

Serializers:

class CitySerializer(serializers.ModelSerializer):
    class Meta:
        model = City
        fields = ('name', )

class StateSerializer(serializers.ModelSerializer):
    cities = CitySerializer(many=True)

    class Meta:
        model = State
        fields = ('name', 'cities')
        filter_class = StateFilter

View:

from rest_framework.generics import ListAPIView, RetrieveAPIView
from .serializers import StateSerializer

class StateList(ListAPIView):
    queryset = State.objects.all()
    serializer_class = StateSerializer
    filter_fields = ('name', 'cities')

The output for ../api/states/ is currently:

 [
     "name": "Florida",
     "cities": [
          "name": "Tampa",
          "name": "St. Petersburg",
          "name": "Orlando"
     ],
     "name": "North Carolina",
     "cities": [
          "name": "Raleigh",
          "name": "Charlotte",
          "name": "Greensboro"
     ]
 ]

How can I filter the cities via a GET call by name such as:

../api/states/?cities=Charlotte

The result of the above should be:

 [
     "name": "North Carolina",
     "cities": [
          "name": "Raleigh",
          "name": "Charlotte",
          "name": "Greensboro"
     ]
 ]
like image 546
Michael B Avatar asked Sep 19 '14 22:09

Michael B


People also ask

How do I filter Queryset in Django REST framework?

The simplest way to filter the queryset of any view that subclasses GenericAPIView is to override the .get_queryset() method. Overriding this method allows you to customize the queryset returned by the view in a number of different ways.


1 Answers

Well, I found out what I was doing wrong. It was in the view. I had not declared filter_class on the view:

from rest_framework.generics import ListAPIView, RetrieveAPIView
from .serializers import StateSerializer
from .filters import StateFilter

class StateList(ListAPIView):
    queryset = State.objects.all()
    serializer_class = StateSerializer
    filter_fields = ('name', 'cities')
    filter_class = StateFilter  # This was missing

I accidentally placed it on the serializer instead.

like image 139
Michael B Avatar answered Sep 17 '22 23:09

Michael B