ThunderHorn
ThunderHorn

Reputation: 2035

Django serializer ManyToMany retrun array of names instead of an array of IDs

My models:

class Category(models.Model):
    name = models.Charfield()..
    code = models.Charfield()...

class Movie(models.Model):
    name = models.Charfield()..
    categories = models.ManyToManyField(Category)

My serializer

class MovieSerializer(serializers.ModelSerialier):
   class Meta:
      model= Movie
      fields = ['name',
               'categories',
      ]

When i get a Movie by id it returns:

[ {"name": "My Movie", "categories": [1, 2, 3], } ]

I want my response to be : .... "categories": ["Fun", "Adventure", ...]

What I've tried

class CategorySerializer(serializers.ModelSerializer):
   class Meta:
      model = Category
      fields = ['name']
  
   def to_representation(self, instance):
      return instance.name

It gives me the expected result, but i dont think it is a clean way to do it

Upvotes: 4

Views: 3095

Answers (2)

Gerges Fikry
Gerges Fikry

Reputation: 1

Add depth = 1 to your serializer.

This will give you something like:

[
  {
    "name": "My Movie",
    "categories": [
      { "id": 1, "name": "Fun", "code": "category_code" }
    ]
  }
]

then you can extract whatever you want from this object.

Upvotes: 0

Hafnernuss
Hafnernuss

Reputation: 2847

Option 1

You can use your models __str__ method for this. Just use a StringRelatedField:

class MovieSerializer(serializers.ModelSerialier):
   categories = serializers.StringRelatedField(many=True)
   class Meta:
      model= Movie
      fields = ['name', 'categories']

and add the __str__ method to your category model:

class Category(models.Model):
    name = models.Charfield()
    code = models.Charfield()

    def __str__(self):
        return self.name

Option 2

Use a custom RelatedField, like described in the docs:

class CategoryListingField(serializers.RelatedField):
    def to_representation(self, value):
        return value.name

class MovieSerializer(serializers.ModelSerialier):
   categories = CategoryListingField(many=True)
   class Meta:
      model= Movie
      fields = ['name', 'categories']

This is close to what you did, just a little bit cleaner, as a RelatedField is designed to accomplish exactly that. Using a custom serializer is not the way to go here, since you dont want to serialize the object itself, but only a specific field from it. Per default, this is the pk (or id), but by specifying your own related field, you can change it to whatever you want.

Upvotes: 7

Related Questions