3
votes

I am having trouble with nested serializers and the Django rest framework. When setting serializer_class to "UserSerializer", the nested data from the "NameSerializer" class isn't appearing. However, when I set serializer_class to "NameSerializer", the data does appear.

The API returns when using UserSerializer:

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
  {
    "id": 1,
    "userName": "[email protected]"
  },
  {
    "id": 2,
    "userName": "[email protected]"
  },
  {
    "id": 3,
    "userName": "[email protected]"
  },
  {
    "id": 4,
    "userName": "[email protected]"
  }
]

What I want it to return:

HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[
  {
    "id": 1,
    "userName": "[email protected]"
    "name": {
      "familyName": "Joe",
      "givenName": "admin",
      "formated": "admin Joe"
    },
  },
  {
    "id": 2,
    "userName": "[email protected]"
    "name": {
      "familyName": "Doe",
      "givenName": "Jane",
      "formated": "Jane Doe"
    },
  },
  {
    "id": 3,
    "userName": "[email protected]"
    "name": {
      "familyName": "Idol",
      "givenName": "Billy",
      "formated": "Billy Idol"
    },
  },
  {
    "id": 4,
    "userName": "[email protected]"
    "name": {
      "familyName": "B",
      "givenName": "User",
      "formated": "User B"
    },
  }
]

views.py

from API.models import Person
from API.serializers import *
from rest_framework import viewsets

class UserViewSet(viewsets.ModelViewSet):
   queryset = Person.objects.all()
   serializer_class = NameSerializer

models.py

class Person(AbstractBaseUser):
    email = models.EmailField(
       verbose_name='email address',
       max_length=255,
       unique=True,
       )
    first_name = models.CharField(max_length=254, blank=True)
    last_name =  models.CharField(max_length=254, blank=True)

serializers.py

class NameSerializer(serializers.ModelSerializer):

  familyName = serializers.CharField(source='last_name')
  givenName = serializers.CharField(source='first_name')
  formatted = serializers.SerializerMethodField()

  class Meta:
      model = Person
      fields = ('familyName', 'givenName', 'formatted',)


  def get_formatted(slef, obj):
      FullName = obj.first_name + '' + obj.last_name
      return FullName


class UserSerializer(serializers.ModelSerializer):

  name = NameSerializer(many=True, readonly=True)
  userName = serializers.EmailField(source='email')

  class Meta:
      model = Person
      fields = ('id', 'userName', 'name')

Any help is appreciated

3

3 Answers

3
votes

You don't need to create NameSerializer serializer. Create a method field in UserSerializer for name field such as:

class UserSerializer(serializers.ModelSerializer):

    userName = serializers.EmailField(source='email')
    name = serializers.SerializerMethodField()

    class Meta:
        model = Person
        fields = ('id', 'userName', 'name')

    def get_name(self, obj):
        name = {
            'familyName': obj.first_name,
            'givenName': obj.last_name,
            'formatted': obj.first_name + ' ' + obj.last_name
        }
        return name

It will give your desired result.

0
votes

This might help you:

class UserSerializer(serializers.ModelSerializer): name = NameSerializer() userName = serializers.EmailField(source='email')

     class Meta:
         model = Person
         fields = ('id', 'userName', 'name')

If the items should be a list, then only you need to pass many=True.

0
votes

Maybe try using SerializerMethodField: Something like this:

class UserSerializer(serializers.ModelSerializer):

    userName = serializers.EmailField(source='email')
    name = serializers.SerializerMethodField()

    class Meta:
        model = Person
        fields = ('id', 'userName', 'name')

    def get_name(self, obj):
        return {
            'familyName': obj.first_name,
            'givenName': obj.last_name,
            'formatted': obj.first_name + ' ' + obj.last_name
        }