Syed Bilal Ali
Syed Bilal Ali

Reputation: 126

Serializing Nested foreign key objects

whoever is reading this, hope you're doing well. I am creating a social media application which includes post in it and likes and comments just like any other social media site, I am trying to send the data from my backend to front end via serializers, the problem I am getting through is I am not able to get the output of whole data but partial data. Following represents my models.py for the objects I am trying to serialize

models.py

class User(AbstractUser):
    contact_no = models.CharField(max_length=15,null=True,blank=True)
    profile_picture=models.ImageField(upload_to=to_upload,default="defaultprofile.jpg")

class Post(models.Model):
    posted_by=models.ForeignKey(User,on_delete=models.CASCADE)
    date= models.DateField(auto_now=True)
    time=models.TimeField(auto_now=True)
    content=models.CharField(max_length=2000)
    media=models.ImageField(default=None,blank=True,upload_to=to_upload_post)

class Like(models.Model):
    Liked_by=models.ForeignKey(User,on_delete=models.CASCADE,related_name="likes")
    post=models.ForeignKey(Post,on_delete=models.CASCADE)
    date = models.DateField(auto_now=True)
    time = models.TimeField(auto_now=True)

and the serializers that I'm using is

serializers.py

class UserSerializer(serializers.ModelSerializer):
   
    class Meta:
        model=User
        fields=['id','username','first_name','last_name','profile_picture']

class LikeSerializer(serializers.ModelSerializer):
    Liked_by=UserSerializer()
    class Meta:
        model=Like
        fields=['Liked_by']

class PostSerializer(serializers.ModelSerializer):
    posted_by=UserSerializer()
    likes=LikeSerializer(many=True)

    class Meta:
        model=Post
        fields=['posted_by','id','content','date','time','media','likes']

This does not raise any errors while importing it but it doesn't give complete data.

The output I'm getting is

 {
   'posted_by': 
              OrderedDict([
                           ('id', 7), 
                           ('username', 'user'), 
                           ('first_name', ''), 
                           ('last_name', ''), 
                           ('profile_picture', '/media/defaultprofile.jpg')]), 
  'id': 4, 
  'content': 'This is a test post for likes', 
  'date': '2020-10-22', 
  'time': '05:34:55.979863', 
  'media': None
}

but what I'm trying to get is

Desired Output

{
   'posted_by': 
              OrderedDict([
                           ('id', 7), 
                           ('username', 'user'), 
                           ('first_name', ''), 
                           ('last_name', ''), 
                           ('profile_picture', '/media/defaultprofile.jpg')]), 
  'id': 4, 
  'content': 'This is a test post for likes', 
  'date': '2020-10-22', 
  'time': '05:34:55.979863', 
  'media': None
  'likes':
          ['Liked_by':
                     OrderedDict([
                           ('id', 1), 
                           ('username', 'user1'), 
                           ('first_name', ''), 
                           ('last_name', ''), 
                           ('profile_picture', '/media/defaultprofile.jpg')
]
)
  
}

Any leads or help or any strategy recommendations would be much appreciated.

Upvotes: 1

Views: 1039

Answers (2)

Ali Asgari
Ali Asgari

Reputation: 850

Try to set the related_name the same way you did for Liked_by field:

post=models.ForeignKey(Post,on_delete=models.CASCADE, related_name='likes')

Unfortunately some exceptions are masked by django rest framework as it tries to catch some of them including AttributeError to perform field existence checks.

Upvotes: 1

Maciej Rogosz
Maciej Rogosz

Reputation: 92

Few things to note:

  1. serializers work on data, not serializer classes. Instead, you need to create SerializerMethodField() and create a getter for it.
  2. To avoid issue with spamming database with requests remember to add .select_related() / .prefetch_related() to your QuerySet.
  3. It's considered a good practice to user lowercase field names :)

example:

class LikeSerializer(serializers.ModelSerializer):
    Liked_by = serializers.SerializerMethodField()
    class Meta:
        model=Like
        fields=['Liked_by']
    
    def get_Liked_by(self, instance):
        return UserSerializer(instance.Liked_by, many=False).data

Upvotes: 1

Related Questions