Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

djangorestframework: Filtering in a related field

Basically, I want to filter out inactive users from a related field of a ModelSerializer. I tried Dynamically limiting queryset of related field as well as the following:

class MySerializer(serializers.ModelSerializer):
  users = serializers.PrimaryKeyRelatedField(queryset=User.objects.filter(active=True), many=True)
  class Meta:
    model = MyModel
    fields = ('users',)

Neither of these approaches worked for just filtering the queryset. I want to do this for a nested related Serializer class as a field (but couldn't even get it to work with a RelatedField).

How do I filter queryset for nested relation?

like image 775
fangsterr Avatar asked Sep 05 '13 00:09

fangsterr


People also ask

How do you use DjangoFilterBackend?

To use DjangoFilterBackend , first install django-filter . Then add 'django_filters' to Django's INSTALLED_APPS : INSTALLED_APPS = [ ... 'django_filters', ... ] Or add the filter backend to an individual View or ViewSet.

What is filter backend?

The DjangoFilterBackend class is used to filter the queryset based on a specified set of fields. This backend class automatically creates a FilterSet (django_filters. rest_framework. FilterSet) class for the given fields. We can also create our own FilterSet class with customized settings.

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.


Video Answer


2 Answers

I'll be curious to see a better solution as well. I've used a custom method in my serializer to do that. It's a bit more verbose but at least it's explicit.

Some pseudo code where a GarageSerializer would filter the nested relation of cars:

class MyGarageSerializer(...):
    users = serializers.SerializerMethodField('get_cars')

    def get_cars(self, garage):
        cars_queryset = Car.objects.all().filter(Q(garage=garage) | ...).select_related()
        serializer = CarSerializer(instance=cars_queryset, many=True, context=self.context)

        return serializer.data

Obviously replace the queryset with whatever you want. You don't always need the to give the context (I used it to retrieve some query parameters in the nested serializer) and you probably don't need the .select_related (that was an optimisation).

like image 114
François Constant Avatar answered Oct 21 '22 19:10

François Constant


One way to do this is to create a method on the Model itself and reference it in the serializer:

#Models.py
class MyModel(models.Model):
    #...
    def my_filtered_field (self):
            return self.othermodel_set.filter(field_a = 'value_a').order_by('field_b')[:10]
#Serialziers.py
class MyModelSerialzer(serializers.ModelSerializer):
    my_filtered_field = OtherModelSerializer (many=True, read_only=True)
    class Meta:
        model   = MyModel
        fields  = [
            'my_filtered_field'             ,
            #Other fields ...
        ]
like image 28
SEDaradji Avatar answered Oct 21 '22 19:10

SEDaradji