Allanrbo Allanrbo - 1 month ago 8
Python Question

Dynamically limiting queryset of related field

Using Django REST Framework, I want to limit which values can be used in a related field in a creation.

For example consider this example (based on the filtering example on , but changed to ListCreateAPIView):

class PurchaseList(generics.ListCreateAPIView)
model = Purchase
serializer_class = PurchaseSerializer

def get_queryset(self):
user = self.request.user
return Purchase.objects.filter(purchaser=user)

In this example, how do I ensure that on creation the purchaser may only be equal to self.request.user, and that this is the only value populated in the dropdown in the form in the browsable API renderer?

Answer Source

I ended up doing something similar to what Khamaileon suggested here. Basically I modified my serializer to peek into the request, which kind of smells wrong, but it gets the job done... Here's how it looks (examplified with the purchase-example):

class PurchaseSerializer(serializers.HyperlinkedModelSerializer):
    def get_fields(self, *args, **kwargs):
        fields = super(PurchaseSerializer, self).get_fields(*args, **kwargs)
        fields['purchaser'].queryset = permitted_objects(self.context['view'].request.user, fields['purchaser'].queryset)
        return fields

    class Meta:
        model = Purchase

permitted_objects is a function which takes a user and a query, and returns a filtered query which only contains objects that the user has permission to link to. This seems to work both for validation and for the browsable API dropdown fields.