How to change viewset retrieve response in Django Rest Framework?

12,837

If you want to modified retrieve functionality of ModelViewset you can overwrite its retrieve method and do what ever you want. mixin's link

class AirportList(viewsets.ModelViewSet):
    queryset = models.Airport.objects.all()
    serializer_class = AirportSerializer
    def retrieve(self, request, *args, **kwargs):
        # do your customization here
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)

How to explore DRF

I think best way to look after any new thing is their codebase. For ModelViewset you should start from viewslink and explore what are the functionality it provide and how i can customize them.

Share:
12,837
murthaA
Author by

murthaA

Updated on June 04, 2022

Comments

  • murthaA
    murthaA almost 2 years

    I'm currently developing a Web App that uses an API as the backend for a University Project.

    And I've read that DRF is the fastest and easiest way to develop and deploy an API, I already followed through their entire official

    documentation and I don't seem to understand how I could the following in their ViewSet and Serializer.

    Here's one endpoint of my API called airports.

    All airports available in the USA

    Returns json/csv list of links to the available airports in the USA.

    • URL

      /airports

    • Method:

      GET

    • Success Response:

      • Code: 200
        Content:

        [
          {
              "airport": {
                  "code": "PHL",
                  "name": "Philadelphia, PA: Philadelphia International",
                "id": 123,
                  "url": "/airports/123"
              },
          {
              "airport": {
                  "code": "AHR",
                  "name": "American Hour Rapid",
              "id": 125,
                  "url": "/airports/125"
          }
          .
          .
          .
        ]
      

    Show Airport Informations

    Returns all links to the carriers operating at a specific airport, a link to the related statistics on a specific month and year and also a link to the airport routes. If in case neither the year or the month are specified, the default will be the one with the most recent date.

    • URL

    /airports/:id

    • Method:

    GET

    • URL Params

      Required:

      id=[integer]

    • Success Response:

    {
        "airport": {
          "code": "PHL",
          "name": "Philadelphia, PA: Philadelphia International",
          "id": 123,
          "url": "/airports/123"
        },
        "routes_link": "/airports/123/routes",
        "carriers": [
            {
              "id": 124,
              "url": "/carriers/124?airport_id=123",
              "statistics_url":"/airports/1carrier=124&statistics='flights'"
            },
            .
            .
            .
          ]
    }
    

    I was able to do /airports properly listing all of the available airports in the database but when using the ViewSet I don't know how to "customize" the response when trying to retrieve information about only one airport specified by the id and in the application the routes are going to be generated dynamically and I was planning to add to the response body and not another field in the model.

    Models:

    class Carrier(models.Model):
        code = models.CharField(max_length=10)
        name = models.TextField()
        #airports = models.ManyToManyField(Airport) 
    
        def __str__(self):
            return self.name
    
    class Airport(models.Model):
        code = models.CharField(max_length=10)
        name = models.TextField()
        carriers = models.ManyToManyField(Carrier, related_name='airports')
    
        def __str__(self):
            return self.name
    

    Serializers:

    class AirportSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = models.Airport
            fields = ('id', 'name', 'code', 'url')
    
    class CarrierSerializer(serializers.HyperlinkedModelSerializer):
        class Meta:
            model = models.Carrier
            fields = ('id', 'name', 'code', 'url')
    

    View:

    class AirportList(viewsets.ModelViewSet):
        queryset = models.Airport.objects.all()
        serializer_class = AirportSerializer
        # @Override something here?
    

    Anyone has a tip on how I could approach this using DRF or any kind of learning material I could use?

  • Mr.L
    Mr.L about 4 years
    Overriding retrieve is not working for me, even after modifying it I am getting the same response, even though I am returning "Hello".
  • Alfarhan Zahedi
    Alfarhan Zahedi about 4 years
    @Mr.L Maybe you are overriding the wrong method. You need to override retrieve() if you are just returning a single instance of the model under consideration. If you are returning a list of instances, try overriding the list() method. You can find its definition in the mixin's link shared in the above answer.