0
votes

My question is around designing a RESTful API with Django Rest Framework. I have the following two data files.

# cars.csv
Escalade, Ford
Outback, Subaru
Fiesta, Ford

# description.csv
new, "Escalade", 2018, "perfect condition"
used, "Escalade", 2016, "in good shape"
used, "Escalade", 2010, "bad condition"

I want a GET-only API endpoint that would output the following:

{
  "model": "Escalade",
  "company": "Ford",
  "year": 2018,
  "details": [
    {
      "condition": "new",
      "description": "perfect condition"
    }
 ]

}

The issue is how to display year so it is displayed up a level from its model position. If I changed the original csv files I could add year to cars.csv but assume I can't do that. How would I configure my serializer to output the desired API endpoint?

This is the model, serializer, view, and url.

# models.py
from django.db import models

class Car(models.Model):
    model = models.CharField(max_length=100)
    company = models.CharField(max_length=100)

class Detail(models.Model):
    year = models.CharField(
    condition = models.CharField(max_length=100)    
    car = models.ForeignKey('Car', related_name='details',
                        on_delete=models.CASCADE,)
    description = models.CharField(max_length=100)


# serializers.py
from rest_framework import serializers
from . import models


class DetailSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        fields = ('year', 'condition', 'description',)
        model = models.Detail


class CarSerializer(serializers.HyperlinkedModelSerializer):
    details = DetailSerializer(many=True, read_only=True)

class Meta:
    fields = ('model', 'company', 'details',)
    model = models.Car

# views.py
from rest_framework import generics

from . import models
from . import serializers


class CarDetail(generics.RetrieveAPIView):
    queryset = models.Detail.objects.all()
    serializer_class = serializers.DetailSerializer


class CarList(generics.ListAPIView):
    queryset = models.Car.objects.all()
    serializer_class = serializers.CarSerializer



# urls.py 
from django.urls import path

from . import views

urlpatterns = [
    path('', views.CarList.as_view()),
    path('<int:pk>', views.CarDetail.as_view()),
]
1

1 Answers

0
votes

Perhaps use a SerializerMethodField.

class CarSerializer(serializers.HyperlinkedModelSerializer):
    details = DetailSerializer(many=True, read_only=True)
    year = serializers.SerializerMethodField()

    class Meta:
        fields = ('model', 'company', 'details', 'year',)
        model = models.Car

    def get_year(self, car):
        return car.details.first().year

You need to be a little bit careful, as the above example assumes that there will always be at least one Detail for a car, and it will use the first it finds.