Django How to Serialize from ManyToManyField and List All

核能气质少年 提交于 2020-12-29 06:58:46

问题


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.


回答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', )



回答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 :)



来源:https://stackoverflow.com/questions/34925690/django-how-to-serialize-from-manytomanyfield-and-list-all

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!