E. Edwards
E. Edwards

Reputation: 418

How to return the first serialized object rather than all in Django?

I have an API (using django-rest-framework) with two models (e.g. Users and Cars).

I'm trying to get the user's latest (highest ID) Car also returned when the User is queried.

I've tried including cars = CarSerializer(many=True) in the User serializer, which returns all cars for that user.

I've tried cars = CarSerializer(many=False), which returns the format I want, but no cars turn up.

Code

car model

class Car(models.Model):
    name = models.TextField(default='')
    year = models.IntegerField(null=True)
    owner = models.ForeignKey('User', related_name='cars')

car serializer

class CarSerializer(serializers.ModelSerializer):

    class Meta:
        model = Car
        fields = ('id', 'name', 'year', 'owner')

user serializer

class UserSerializer(serializers.ModelSerializer):
    car = CarSerializer(many=True)

    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'car')

car view

class CarViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Car.objects.all()
    serializer_class = CarSerializer

user view

class UserViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

What I'm looking for

Given two cars belonging to the user with an ID of 1:

id: 1
owner: 1
name: "kinda okay car"
year: 2012

id: 2
owner: 1
name: "the fastest one"
year: 2020

JSON Result of GET /users/1

{
  "id": 1,
  "first_name": "Bob",
  "last_name": "McFastCar",
  "car": {
    "name": "the fastest one",
    "year": 2020
  }
}

What I currently get

JSON Result of GET /users/1

{
  "id": 1,
  "first_name": "Bob",
  "last_name": "McFastCar",
  "cars": [
    {
      "id": 2,
      "owner": 1
      "name": "the fastest one",
      "year": 2020
    },
    {
      "id": 1,
      "owner": 1
      "name": "kinda okay car",
      "year": 2012
    }
  ],
}

Thanks, I wheely hope you can help drive me towards a solution.

Upvotes: 3

Views: 2887

Answers (3)

wencakisa
wencakisa

Reputation: 5958

You can actually create a @property in your User model that returns the last car only:

class User:
    ...

    @property
    def last_car(self):
        return self.cars.last()

And then in the UserSerializer you can just serialize this property:

class UserSerializer:
    last_car = CarSerializer(read_only=True)

    class Meta:
        model = User
        fields = (..., 'last_car')

This would do the trick.


P.S. : If you still want your latest car entry to be serialized as "car": { ... } but not "last_car": { ... } , you can use the source attribute on the CarSerializer itself:

class UserSerializer:
    car = CarSerializer(source='last_car', read_only=True)
    ...

Upvotes: 5

Mehran Nouri
Mehran Nouri

Reputation: 126

You can write UserSerializers like bellow

class UserSerializer(serializers.ModelSerializer):
    cars = serializers.SerializerMethodField()

    class Meta:
        model = User
        fields = ('id', 'first_name', 'last_name', 'cars')

    def get_cars(self, instance):
        cars = instance.cars.all().order_by('-year')
        return CarSerializer([cars[0], ], many=True).data

and calling GET /users/1 will return results like this

{
    "id": 2,
    "first_name": "Bob",
    "last_name": "McFastCar",
    "cars": [
        {
            "id": 2,
            "name": "the fastest one",
            "year": 2020,
            "owner": 2,
            "first_name": "Bob"
        }
    ]
}

The bellow line gave me an unknown error so I've written it with many=True

return CarSerializer(cars, many=False).data

Upvotes: 0

Amine Messaoudi
Amine Messaoudi

Reputation: 2299

The CarSerializer must be linked with a queryset or an object otherwise it will return all objects

# get the car object with the highest using order_by
car =  Car.objects.all().order_by('-id')[0]
# build a car serializer from the car object
car_serializer = CarSerializer(car, many=False)

Upvotes: 1

Related Questions