Django How to Serialize from ManyToManyField and List All

12,767

Solution 1

I think what you need is the nested serializer:

class FollowerSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source='user__username')

    class Meta:
        model = UserProfile
        fields = ('username', )


class FollowerSerializer(serializers.ModelSerializer):
    followers = FollowerSerializer(many=True, read_only=True)

    class Meta:
        model = UserProfile
        fields = ('followers', )

Solution 2

I used nested relationships in this link. Django Rest Framework Nested Relationships

Added a new serializer for only username of the user and also changed the other serializer.

# serializes only usernames of users
class EachUserSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source='user.username')

    class Meta:
        model = UserProfile
        fields = ('username',)

class FollowerSerializer(serializers.ModelSerializer):
    followers = EachUserSerializer(many=True, read_only= True)
    followings = EachUserSerializer(many=True,read_only=True)

    class Meta:
        model = UserProfile
        fields = ('followers','followings')

Output was just what was I looking for:

{
  "followers": [],
  "followings": [
    {
      "username": "sneijder"
    },
    {
      "username": "drogba"
    }
  ]
}

Thank you for your help anyway :)

Share:
12,767
Cagatay Barin
Author by

Cagatay Barin

Updated on June 04, 2022

Comments

  • Cagatay Barin
    Cagatay Barin almost 2 years

    I'm developing a mobile application backend with Django 1.9.1 I implemented the follower model and now I want to list all of the followers of a user but I'm currently stuck to do that. I also use Django Rest Framework.

    This is my UserProfile model

    class UserProfile(models.Model):
        # Linking UserProfile to User model.
        user = models.OneToOneField(User)
        city = models.CharField(null=True, max_length=30, blank=True)
        gender = models.CharField(null=True, max_length=10, blank=True) # m for male, f for female
        # TODO: Fix the picture later.
        #  picture = models.ImageField(upload_to='profile_images', blank=True)
        age = models.IntegerField(null=True, blank=True)
        caption = models.CharField(null=True, max_length=40, blank=True)
        following_count = models.IntegerField(default=0)
        follower_count = models.IntegerField(default=0)
        post_count = models.IntegerField(default=0)
        like_count = models.IntegerField(default=0)
        date = models.DateTimeField(default=datetime.now(), blank=True)
        is_protected = models.BooleanField(default=False)
        is_facebook_created_user = models.BooleanField(default=False)
        facebook_id = models.CharField(default='', blank=True, max_length=350)
        picture_url = models.URLField(blank=True, max_length=100, null=True)
        followings = models.ManyToManyField('self', related_name='following', symmetrical=False)
        followers = models.ManyToManyField('self', related_name='follower', symmetrical=False)
        blocking = models.ManyToManyField('self', related_name='block', symmetrical=False)
        blocked_by = models.ManyToManyField('self', related_name='blocked', symmetrical=False)
    
        def block_user(self,username):
                other = UserProfile.objects.get(user__username=username)
                if not self.is_blocking(username):
                    self.blocking.add(other)
                    other.blocked_by.add(self)
                    return True
                else:
                    return False
    
        def unblock_user(self, username):
                other = UserProfile.objects.get(user__username=username)
                if self.is_blocking(username):
                    self.blocking.remove(other)
                    other.blocked_by.remove(self)
                    return True
                else:
                    return False
    
        def follow_user(self, username):
                other = UserProfile.objects.get(user__username=username)
                if not self.is_following(username):
                    self.followings.add(other)
                    self.following_count = self.followings.all().count()
                    self.save()
                    other.followers.add(self)
                    other.follower_count = other.followers.all().count()
                    other.save()
                    return True
                else:
                    return False
    
        def unfollow_user(self, username):
                other = UserProfile.objects.get(user__username=username)
                if self.is_following(username):
                    self.followings.remove(other)
                    self.following_count = self.followings.all().count()
                    self.save()
                    other.followers.remove(self)
                    other.follower_count = other.followers.all().count()
                    other.save()
                    return True
                else:
                    return False
    
        def is_blocking(self,username):
            return self.blockings.all().filter(user__username=username).exists()
    
        def is_blocked_by(self,username):
            return self.blocked_by.all().filter(user__username=username).exists()
    
        def is_following(self, username):  #returns Bool
            return self.followings.all().filter(user__username=username).exists()
    
        def is_followed_by(self, username):  #returns Bool
            return self.followers.all().filter(user__username=username).exists()
    
        def __unicode__(self):
            return self.user.username
    
        def get_token(self):
            try:
                token = Token.objects.get(user_id=self.user_id)
            except:
                token = 'error'
            return token
        def get_username(self):
            return self.user.username
    

    As you see, I user ManyToManyField for followers. Now I want to list followers of a user but I don't want to list just all of their information since it's unnecessary. I just want to list their usernames because no need for whole information and it's just a waste.

    Here is my followers view.

    @api_view(['GET'])
    def get_followers(request):
        username = request.query_params.get('username', None)
        if username is not None:
            if        UserProfile.objects.all().filter(user__username=username).exists():
                wanted = UserProfile.objects.get(user__username=username)
                followers = wanted.followers.all()
                serializer = FollowerSerializer(followers)
                return JsonResponse(serializer.data)
            else:
                return JsonResponse({"result": "user_does_not_exist"})
        else:
            #TODO: return current user's followers
            return JsonResponse({"result": "provide_username"})
    

    Also I added a serializer for only followers of user.

    class FollowerSerializer(serializers.ModelSerializer):
        class Meta:
            model = UserProfile
            field = ('followers',)
    

    The problem is, it just lists the all of the user information and it doesn't give usernames but it only lists their id's which i can't do anything.

    I forgot to mention that I did think of using ListAPIView but I can't get the username parameter with that. If there is a way of getting the parameter, I could also use ListAPIView for followers.

    How can I fix this problem and list only their usernames? Any help will be appreciated.