0

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": "opeyemiodedeyi@gmail.com",
        "fullname": "opeyemiodedeyi"
    },
    {
        "pk": 2,
        "email": "odedeyiopeyemi94@gmail.com",
        "fullname": "opeyemi odedeyi"
    }
]

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

Opeyemi Odedeyi
  • 766
  • 1
  • 10
  • 38

1 Answers1

1

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
JPG
  • 82,442
  • 19
  • 127
  • 206
  • thanks for this, but which of these two methods would you recommend to use? – Opeyemi Odedeyi Nov 23 '19 at 15:39
  • I would recommend changing the related_name to **`profiles`** (see, it's plural) and use the same related name in serializer also, since `Users` can have multiple `profiles` according to your DB structure. – JPG Nov 23 '19 at 15:43
  • for some reason it isn't working for me, please could you show what to change in the serializer, Thank you – Opeyemi Odedeyi Nov 23 '19 at 15:58
  • okay, it kinda works now, but all the fields are showing null. that is the current problem – Opeyemi Odedeyi Nov 23 '19 at 18:38
  • Please ask a new question since your new question and OP are different – JPG Nov 23 '19 at 18:40