简体   繁体   中英

How to limit the queryset of related fields of serializer based on some request parameters in Django Rest Framework

I have three models Transaction , Business , and Location . They are defined as follows:

class Business(models.Model): 
    # Can have zero or more locations. A user can have many businesses.
    name  = models.CharField(max_length=200, validators=[MinLengthValidator(1)])
    # ... and some other fields ...

class Location(models.Model): 
    # Must have one business. Locations cannot exist without a business
    suburb   = models.CharField(max_length=150, validators=[MinLengthValidator(1)])
    business = models.ForeignKey(Business, related_name='locations')
    # ... and some other fields ...

class Transaction(models.Model): 
    # Can have zero or one business
    # Can have zero or one location and the location must belong to the business. If business is empty, location must be empty
    business = models.ForeignKey(Business, on_delete=models.SET_NULL, null=True, blank=True, related_name='transactions')
    location = models.ForeignKey(Location, on_delete=models.SET_NULL, null=True, blank=True, related_name='transactions')
    # ... and some other fields ...

And the serializers:

class BusinessRelatedField(serializers.PrimaryKeyRelatedField):

    def get_queryset(self):
        owner = get_owner_from_context(self.context)
        return Business.objects.filter(owner=owner)

class LocationRelatedField(serializers.PrimaryKeyRelatedField):

    def get_queryset(self):
        params = self.context['request'].query_params
        business_params = params.get('business')
        if business_params is not None:
            owner = get_owner_from_context(self.context)
            return Location.objects.filter(owner=owner, business=business_params)
        else:
            return None

class TransactionSerializer(serializers.ModelSerializer):

    business = BusinessRelatedField(required=False, allow_null=True)
    location = LocationRelatedField(required=False, allow_null=True)

The problem I was facing was that I didn't know how to restrict the value of Location based on the value of Business . I was manually performing this check inside TransactionSerializer 's validate method until it occurred to me to create a PrimaryKeyRelatedField subclass and override the get_queryset method. This seemed like a better approach to me (and it's actually working) but I'd like to know if this is the 'normal' way of doing it.

The other problem I'm now facing is that the 'browsable API' no longer shows any choices for Location which I feel is a hint that I might be doing something wrong.

Any help would be appreciated.

You can override the get_fields() method of the serializer and modify the queryset for business and location fields to the desired values.

get_fields() method is used by the serializer to generate the field names -> field instances mapping when .fields property is accessed on it.

class TransactionSerializer(serializers.ModelSerializer):

    class Meta:
        model = Transaction
        fields = (.., business, transaction)

    def get_fields(self):
        # get the original field names to field instances mapping
        fields = super(TransactionSerializer, self).get_fields()

        # get the required parameters
        owner = get_owner_from_context(self.context)
        business_params = self.context['request'].query_params.get('business')

        # modify the queryset
        fields['business'].queryset = Business.objects.filter(owner=owner)
        fields['location'].queryset = Location.objects.filter(owner=owner, business=business_params)

        # return the modified fields mapping
        return fields

This is a very late answer, however it would not be different back then.

With the information you provided (in the comments as well) and AFAIK there is no way of doing this unless you manipulate the javascript code of the browsable API's templates and add ajax calling methods to it.

DRF browsable API and DRF HTML and forms may help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM