Search code examples
pythondjangodjango-rest-frameworkdjango-rest-auth

my profile object is not getting serialized in the user serializer


I am using Django rest auth to authenticate my users, that works well. how my model is set up is that I have the custom user model for authentication and I also have a profile model that gets created with a signal.

I want that when the users are fetched in its URL, the profile for that user is also called an object in user.

my models.py (I didnt include some models like the user managers, skill, e.t.c as i felt they werent relevant)

class User(AbstractBaseUser, PermissionsMixin):
    username = None
    email = models.EmailField(max_length=254, unique=True)
    fullname = models.CharField(max_length=250)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    last_login = models.DateTimeField(null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)


    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['fullname']

    objects = UserManager()


class Profile(models.Model):
    '''
    Note:
    profile photo is expecting photos link gotten from cloudnairy from the frontend
    - The height is calculated in feets and inches
    - Need to sort out location (lives in)
    - Need to add an age function
    - Need to add achievemnet as a foreign field 
    - Need to add education also as a foreign field
    - Add follow functionality
    '''
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    date_of_birth = models.DateField(blank=True, verbose_name="DOB", null=True)
    bio = models.TextField(max_length=500, blank=True, null=True)
    profile_photo = models.CharField(blank=True, max_length=300, null=True)
    skills = models.ManyToManyField(Skill)
    sex = models.CharField(max_length=1, choices=SEX, blank=True, null=True)
    type_of_body = models.CharField(max_length=8, choices=BODYTYPE, blank=True, null=True)
    feet = models.PositiveIntegerField(blank=True, null=True)
    inches = models.PositiveIntegerField(blank=True, null=True)
    lives_in = models.CharField(max_length=50, blank=True, null=True)
    updated_on = models.DateTimeField(auto_now_add=True)

the serializers.py code

class ProfileSerializer(serializers.ModelSerializer):

    class Meta:
        model = Profile
        fields = "__all__"

        read_only_fields = ('pk',)


class CustomUserDetailsSerializer(serializers.ModelSerializer):

    profile = ProfileSerializer(read_only=True)

    class Meta:
        model = User
        fields = ('pk', 'email', 'fullname', 'profile')
        read_only_fields = ('email', 'fullname', 'profile')

view.py

class ListUsersView(APIView):

    permission_classes = [AllowAny]

    def get(self, request):
        user = User.objects.all()
        serializer = CustomUserDetailsSerializer(user, many=True)
        return Response(serializer.data)

urls.py

url(r'^list-users/$', ListUsersView.as_view(), name='list-users'),

the JSON response i get

[
    {
        "pk": 1,
        "email": "[email protected]",
        "fullname": "opeyemiodedeyi"
    },
    {
        "pk": 2,
        "email": "[email protected]",
        "fullname": "opeyemi odedeyi"
    }
]

how do I get the profiles to show in the response?


Solution

  • Method-1

    Use source (DRF doc) argument

    class CustomUserDetailsSerializer(serializers.ModelSerializer):
        profile = ProfileSerializer(read_only=True, source="profile_set")
    
        class Meta:
            model = User
            fields = ('pk', 'email', 'fullname', 'profile')
            read_only_fields = ('email', 'fullname', 'profile')

    Since Profile is in reverse relation with User, you need to specify the reverse lookup, which is profile_set

    Method-2

    Change related_name (Django doc) in models,

    class Profile(models.Model):
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profile')
        ...

    Recommended Changes

    # models.py
    class Profile(models.Model):
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profiles')
        ...
    
    
    # serializers.py
    class CustomUserDetailsSerializer(serializers.ModelSerializer):
        profiles = ProfileSerializer(read_only=True)
    
        class Meta:
            model = User
            fields = ('pk', 'email', 'fullname', 'profiles')
            read_only_fields = ('email', 'fullname', 'profiles')

    References

    1. What is reverse relationship?
    2. Django: Many-To-One Relation