I'm a student studying django rest framework
I'm making a simple sns with django rest framework
I need follower-following system. So, I tried to make it but there is some trouble
First this is my user model with AbstractBaseUser and PermissionsMixin
class User(AbstractBaseUser, PermissionsMixin):
user_id = models.CharField(max_length=100, unique=True, primary_key=True)
name = models.CharField(max_length=100)
created_at = models.DateTimeField(auto_now_add=True)
is_staff = models.BooleanField(default=False)
followers = models.ManyToManyField('self', related_name='follower',blank=True)
following = models.ManyToManyField('self', related_name='following',blank=True)
profile_image = models.ImageField(blank=True)
the field followers is people who follows me and following is whom i follow
When i add following with this APIView class
class AddFollower(APIView):
permission_classes = [IsAuthenticated, ]
def post(self, requset, format=None):
user = User.objects.get(user_id=self.request.data.get('user_id'))
follow = User.objects.get(user_id=self.request.data.get('follow'))
user.following.add(follow)
user.save()
follow.followers.add(user)
follow.save()
print(str(user) + ", " + str(follow))
return JsonResponse({'status':status.HTTP_200_OK, 'data':"", 'message':"follow"+str(follow.user_id)})
The user_id is me and the follow is whom i want to follow
I want to add follow to user_id's following field and add user_id to follow's followers field
But it does not work
What i want for result is like this (with user information api)
{
"followers": [],
"following": [
"some user"
],
}
some user's user info
{
"followers": [
"user above"
],
"following": [
],
}
But real result is like this
{
"followers": [
"some user"
],
"following": [
"some user"
],
}
some user's user info
{
"followers": [
"user above"
],
"following": [
"user above"
],
}
this is not what i want
I have no idea with this problem i need some help
Thank you
models.py
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
followers = models.ManyToManyField('self', symmetrical=False,
blank=True)
def count_followers(self):
return self.followers.count()
def count_following(self):
return User.objects.filter(followers=self).count()
I would design it in different way.
I would not add the information to the User
model but explicitly create another table to store information about "followers" and "following".
Schema of the table would be:
class UserFollowing(models.Model):
user_id = models.ForeignKey("User", related_name="following")
following_user_id = models.ForeignKey("User", related_name="followers")
# You can even add info about when user started following
created = models.DateTimeField(auto_now_add=True)
Now, in your post method implementation, you would do only this:
UserFollowing.objects.create(user_id=user.id,
following_user_id=follow.id)
And then, you can access following and followers easily:
user = User.objects.get(id=1) # it is just example with id 1
user.following.all()
user.followers.all()
And you can then create constraint so user cannot follow the same user twice. But i leave this up to you ( hint: unique_together )
The above solutions are fine and optimal, but I would like to supply a detailed solution for anyone who wants to implement such functionality.
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class UserFollowing(models.Model):
user_id = models.ForeignKey(UserModel, related_name="following", on_delete=models.CASCADE)
following_user_id = models.ForeignKey(UserModel, related_name="followers", on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['user_id','following_user_id'], name="unique_followers")
]
ordering = ["-created"]
def __str__(self):
f"{self.user_id} follows {self.following_user_id}"
class UserFollowingViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticatedOrReadOnly,)
serializer_class = UserFollowingSerializer
queryset = models.UserFollowing.objects.all()
class FollowingSerializer(serializers.ModelSerializer):
class Meta:
model = UserFollowing
fields = ("id", "following_user_id", "created")
class FollowersSerializer(serializers.ModelSerializer):
class Meta:
model = UserFollowing
fields = ("id", "user_id", "created")
from django.contrib.auth import get_user_model
User = get_user_model()
class UserSerializer(serializers.ModelSerializer):
following = serializers.SerializerMethodField()
followers = serializers.SerializerMethodField()
class Meta:
model = User
fields = (
"id",
"email",
"username",
"following",
"followers",
)
extra_kwargs = {"password": {"write_only": True}}
def get_following(self, obj):
return FollowingSerializer(obj.following.all(), many=True).data
def get_followers(self, obj):
return FollowersSerializer(obj.followers.all(), many=True).data
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With