Shubham Gupta
Shubham Gupta

Reputation: 159

Auto calculate and return a field based on request in Django rest framework

I have a list of books with pincode of the location it was added from. I am getting a post request with pincode of user who wants to get such list. The list needs to be sorted according to the distance from the user.

Although I have a function to calculate the distance, I want to return a dynamic field named 'distance' in response.

My Book models is like:-

class Book(TimestampedModel):
user = models.ForeignKey(
    settings.AUTH_USER_MODEL,
    on_delete=models.SET_NULL,
    null=True
)
name = models.CharField(max_length=20, blank=True)
desc = models.CharField(max_length=140, blank=True)
is_active = models.BooleanField(default=True, blank=False)
price = models.IntegerField(null=True)
pincode = models.IntegerField(null=False)

My serializer is like:-

class BookSerializer(serializers.ModelSerializer):
"""Serializer for book object"""

class Meta:
    model = Book
    fields = ('id', 'user', 'name', 'desc', 'is_active', 'sold_to', 'is_sold',
              'age', 'price', 'created_at', 'updated_at', 'pincode')

and my view looks like:-

class BookViewSet(viewsets.ModelViewSet):
serializer_class = serializers.BookSerializer
queryset = Book.objects.all()

query_params = self.request.query_params

def get_queryset(self):
    queryset = Book.objects.all()
    
    if('pincode' in query_params):
        pincode = query_params['pincode']
        try:
            for counter, instance in enumerate(queryset):
                instance.distance = dist.query_postal_code(
                    pincode, instance.pincode)
            queryset = sorted(queryset, key=attrgetter('distance'))
        except Exception as ex:
            print(ex)

    return queryset

As you can see, I am able to calculate the distance in the view, I am not sure how to send this in response.

Please help me I will definitely help you some day :P

Upvotes: 0

Views: 1270

Answers (2)

Shubham Gupta
Shubham Gupta

Reputation: 159

Finally, I have managed to do return a custom field. Following changes were made to my view and serializer.

  1. Passing user's pincode (request's contextual info) to my serializer through context in serializer

     def list(self, request):
             queryset = self.get_queryset()
    
             serializer = serializers.BookDetailSerializer(
                 queryset, context={'query_params': request.query_params}, many=True)
    
             return Response(serializer.data)
    
  2. Accessed Pincode through the passed context in distance function defined in serialzer:-

    pincode = self.context['query_params']['pincode']

PS - Thanks Reshab Das for giving some directions

Upvotes: 0

Reshab Das
Reshab Das

Reputation: 170

Use this code in serializer:

class BookSerializer(serializers.ModelSerializer):
    distance = serializers. SerializerMethodField()

    @property
    def get_query_pincode(self):
        return self.context['request'].query_params.get('pincode', None)

    def get_distance(self, obj):
        if self.get_query_pincode:
            # Your distance calcualting code here
            return distance
        return None

Next in the Meta class:

class Meta:
    model = Book
    fields = ('id', 'user', 'name', 'desc', 'is_active', 'sold_to', 'is_sold',
              'age', 'price', 'created_at', 'updated_at', 'pincode', 'distance')

You will need to add the new field in fields attribute and since its not an actual model field, SerializerMethodField is read only field.

Hope this helps!

Upvotes: 2

Related Questions