4👍
You might want to filter the queryset to ensure that only results relevant to the currently authenticated user making the request are returned.
You can do so by filtering based on the value of request.user.
For example:
from myapp.models import Purchase
from myapp.serializers import PurchaseSerializer
from rest_framework import generics
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
user = self.request.user
return Purchase.objects.filter(purchaser=user)
EDIT
You can subclass the ListSerializer and overwrite the to_representation
method.
By default the to_representation
method calls data.all()
on the nested queryset. So you effectively need to make data = data.filter(**your_filters)
before the method is called. Then you need to add your subclassed ListSerializer as the list_serializer_class on the meta of the nested serializer.
1- subclass ListSerializer
, overwriting to_representation
and then calling super
2- Add subclassed ListSerializer
as the meta list_serializer_class
on the nested Serializer.
Code relevant to yours:
class FilteredListSerializer(serializers.ListSerializer):
def to_representation(self, data):
data = data.filter(user=self.request.user, edition__hide=False)
return super(FilteredListSerializer, self).to_representation(data)
class OrganizationSerializer(serializers.ModelSerializer):
class Meta:
list_serializer_class = FilteredListSerializer
model = GroupProfile
fields = ('title','slug',)
class DepartmentSerializer(serializers.ModelSerializer):
organizations = OrganizationSerializer(many=True, read_only=True)
class Meta:
model = DepartmentModel
fields = ('title', 'organizations',)
class SectorSerializer(serializers.ModelSerializer):
# title = serializers.CharField()
departments = DepartmentSerializer(many=True, read_only=True)
class Meta:
model = SectorModel
fields = ('title','departments',)
0👍
Thanks to @ans2human for the inspiration behind this answer.
Here’s a new approach that is working great for me. I have several Model
s with is_active = BooleanField(...)
that I need to filter out in nested relationships.
NOTE: this solution does not filter out results on non-list fields. for that, you should look to the primary queryset
on your View
The core of the work is done by overloading the to_representation()
function on a custom ListSerializer
, and the many_init
on an accompanying custom ModelSerializer
:
class FilteredListSerializer(serializers.ListSerializer):
filter_params:dict
def __init__(self, *args, filter_params:dict={"is_active":True}, **kwargs):
super().__init__(*args, **kwargs)
self.filter_params = filter_params
def set_filter(self, **kwargs):
self.filter_params = kwargs
def to_representation(self, data):
data = data.filter(**self.filter_params)
return super().to_representation(data)
class FilteredModelSerializer(serializers.ModelSerializer):
LIST_SERIALIZER_KWARGS = serializers.LIST_SERIALIZER_KWARGS + ("filter_params",)
LIST_ONLY_KWARGS = ('allow_empty', 'filter_params')
@classmethod
def many_init(cls, *args, **kwargs):
list_kwargs = dict()
for arg in cls.LIST_ONLY_KWARGS:
value = kwargs.pop(arg, None)
if value is not None:
list_kwargs[arg] = value
child_serializer = cls(*args, **kwargs, **({"read_only":True} if "read_only" not in kwargs else dict()))
list_kwargs['child'] = child_serializer
list_kwargs.update({
key: value for key, value in kwargs.items()
if key in cls.LIST_SERIALIZER_KWARGS
})
meta = getattr(cls, 'Meta', None)
list_serializer_class = getattr(meta, 'list_serializer_class', FilteredListSerializer)
return list_serializer_class(*args, **list_kwargs)
Then, your custom ModelSerializer
for whatever view would instead just extend FilteredModelSerializer
instead.
class ChildSerializer(FilteredModelSerializer):
is_active = BooleanField() # not strictly necessary, just for visibilty
... # the rest of your serializer
class ParentSerializer(serializers.ModelSerializer):
children = ChildSerializer(many=True)
...# the rest of your parent serializer
Now, the children
field on the ParentSerializer will filter for is_active = True
.
If you have a custom query that you wanted to apply, you can do so by providing a dict
of filter params in the standard queryset
format:
class ParentSerializer(serializers.ModelSerializer):
children = ChildSerializer(many=True, filter_params={"my_field":my_value, "my_datetime__gte": timezone.now()})
...# the rest of your parent serializer
Alternatively, one could also utilize the set_filter(...)
method on the FilteredListSerializer
after instantiating the field, like so. This will yield a more familiar format to the original QuerySet.filter(...)
style:
class ParentSerializer(serializers.ModelSerializer):
children = ChildSerializer(many=True)
children.set_filter(my_field=my_value, my_datetime__gte=timezone.now())
...# the rest of your parent serializer