我会以不同的方式设计它。
我不会将信息添加到User
模型中,而是显式创建另一个表来存储有关“关注者”和“关注者”的信息。
表的架构为:
class UserFollowing(models.Model):
user_id = models.ForeignKey("User",related_name="following",null=False,blank=False)
following_user_id = models.ForeignKey("User",related_name="followers",blank=False)
# You can even add info about when user started following
created = models.DateTimeField(auto_now_add=True)
现在,在您的post方法实现中,您只需执行以下操作:
UserFollowing.objects.create(user_id=user.id,following_user_id=follow.id)
然后,您可以轻松访问关注者和关注者:
user = User.objects.get(id=1) # it is just example with id 1
user.following.all()
user.followers.all()
然后您可以创建约束,以便用户不能再跟随同一用户两次。但是我把这个留给你(提示:unique_together)
,
以上解决方案是最佳且最优的,但是我想为想要实现这种功能的任何人提供详细的解决方案。
中介模型
from django.contrib.auth import get_user_model
UserModel = get_user_model()
class UserFollowing(models.Model):
user_id = models.ForeignKey(UserModel,on_delete=models.CASCADE)
following_user_id = models.ForeignKey(UserModel,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}"
跟踪并取消关注的SERIALIZER
您的关注和取消关注的视图
class UserFollowingViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticatedOrReadOnly,)
serializer_class = UserFollowingSerializer
queryset = models.UserFollowing.objects.all()
自定义关注者序列化程序和FollowerSerializer
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")
您的UserSerializer
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
,
我创建了一个类似于 Instagram 的关注和取消关注系统。
功能:
- 如果启用私人帐户 --> 发送关注请求。
- 如果用户在阻止列表中 --> 他们不能关注对方用户。
- 用户可以查看待处理的请求、发送的请求列表、阻止的用户
清单等
让我们开始吧:
Models.py:
class Profile(models.Model):
user = models.OneToOneField(to = User,on_delete=models.CASCADE,related_name='profile')
.......
private_account = models.BooleanField(default = False)
followers = models.ManyToManyField('self',blank=True,related_name='user_followers',symmetrical=False)
following = models.ManyToManyField('self',related_name='user_following',symmetrical=False)
panding_request = models.ManyToManyField('self',related_name='pandingRequest',symmetrical=False)
blocked_user = models.ManyToManyField('self',related_name='user_blocked',symmetrical=False)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s' %(self.user)
- 在这里您可以关注、取消关注、发送关注请求、接受关注请求、
拒绝请求,您可以删除您的关注者。
- 从前端侧传递相反的用户配置文件 id 和 类型
行动(关注,取消关注......)。
views.py:
class FollowUnfollowView(APIView):
permission_classes = [IsAuthenticated]
def current_profile(self):
try:
return Profile.objects.get(user = self.request.user)
except Profile.DoesNotExist:
raise Http404
def other_profile(self,pk):
try:
return Profile.objects.get(id = pk)
except Profile.DoesNotExist:
raise Http404
def post(self,request,format=None):
pk = request.data.get('id') # Here pk is opposite user's profile ID
req_type = request.data.get('type')
current_profile = self.current_profile()
other_profile = self.other_profile(pk)
if req_type == 'follow':
if other_profile.private_account:
other_profile.panding_request.add(current_profile)
return Response({"Requested" : "Follow request has been send!!"},status=status.HTTP_200_OK)
else:
if other_profile.blocked_user.filter(id = current_profile.id).exists():
return Response({"Following Fail" : "You can not follow this profile becuase your ID blocked by this user!!"},status=status.HTTP_400_BAD_REQUEST)
current_profile.following.add(other_profile)
other_profile.followers.add(current_profile)
return Response({"Following" : "Following success!!"},status=status.HTTP_200_OK)
elif req_type == 'accept':
current_profile.followers.add(other_profile)
other_profile.following.add(current_profile)
current_profile.panding_request.remove(other_profile)
return Response({"Accepted" : "Follow request successfuly accespted!!"},status=status.HTTP_200_OK)
elif req_type == 'decline':
current_profile.panding_request.remove(other_profile)
return Response({"Decline" : "Follow request successfully declined!!"},status=status.HTTP_200_OK)
elif req_type == 'unfollow':
current_profile.following.remove(other_profile)
other_profile.followers.remove(current_profile)
return Response({"Unfollow" : "Unfollow success!!"},status=status.HTTP_200_OK)
elif req_type == 'remove': # You can remove your follower
current_profile.followers.remove(other_profile)
other_profile.following.remove(current_profile)
return Response({"Remove Success" : "Successfuly removed your follower!!"},status=status.HTTP_200_OK)
# Here we can fetch followers,following detail and blocked user,pending request,sended request..
def patch(self,format=None):
req_type = request.data.get('type')
if req_type == 'follow_detail':
serializer = FollowerSerializer(self.current_profile())
return Response({"data" : serializer.data},status=status.HTTP_200_OK)
elif req_type == 'block_pending':
serializer = BlockPendinSerializer(self.current_profile())
pf = list(Profile.objects.filter(panding_request = self.current_profile().id).values('id','user__username','profile_pic','overall_pr'))
return Response({"data" : serializer.data,"Sended Request" :pf},status=status.HTTP_200_OK)
# You can block and unblock user
def put(self,format=None):
pk = request.data.get('id') # Here pk is oppisite user's profile ID
req_type = request.data.get('type')
if req_type == 'block':
self.current_profile().blocked_user.add(self.other_profile(pk))
return Response({"Blocked" : "This user blocked successfuly"},status=status.HTTP_200_OK)
elif req_type == 'unblock':
self.current_profile().blocked_user.remove(self.other_profile(pk))
return Response({"Unblocked" : "This user unblocked successfuly"},status=status.HTTP_200_OK)
serializers.py:
class EachUserSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = Profile
fields = ('id','username','profile_pic')
read_only_fields = ('id','profile_pic')
class FollowerSerializer(serializers.ModelSerializer):
followers = EachUserSerializer(many=True,read_only= True)
following = EachUserSerializer(many=True,read_only=True)
class Meta:
model = Profile
fields = ('followers','following')
read_only_fields = ('followers','following')
class BlockPendinSerializer(serializers.ModelSerializer):
panding_request = EachUserSerializer(many=True,read_only= True)
blocked_user = EachUserSerializer(many=True,read_only=True)
class Meta:
model = Profile
fields = ('panding_request','blocked_user')
read_only_fields = ('panding_request','blocked_user')
urls.py:
from django.urls.conf import path
from .views import *
urlpatterns = [
.....
path('follow_unfollow/',FollowUnfollowView.as_view(),name = "follow_unfollow"),]
如果对任何步骤有任何疑问,请发表评论。我将简要描述。
,
这就是我解决问题的方式。
上面有一个很好的答案,但是有人需要它的详细信息。所以我写这个
我删除了字段关注者,并在用户模型中关注了。并创建了新模型UserFollowing。
您可以在“热情的马丁”的回答中看到此模型。我没有使用任何序列化程序来创建对象。
仅需要两个视图(关注,取消关注)。
在关注视图中
UserFollowing.objects.create(user_id=user.id,following_user_id=follow.id)
以此我们可以创建关注者-跟随者关系。
使用这种关系的方式
在用户信息视图中
following_data = UserFollowingSerializer(qs.following.all(),many=True)
followers_data = UserFollowingSerializer(qs.followers.all(),many=True)
return JsonResponse({'status':status.HTTP_200_OK,'data':{'user':serializer.data,'following':following_data.data,'followers':followers_data.data},"message":"success"})
我通常使用JsonResponse进行响应。
serializer.data和qs是用户对象
在UserFolowingSerializer中
fields = '__all__'
我用了这个。
,
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()
,
很好的答案。对我来说,要么是@GST Talib 的答案,要么是不使用 self
的非常相似的答案
following = models.ManyToManyField('User',related_name='followers')
这样,当您添加 user1.following.add(user2)
时,您可以看到 user2.followers
中反映的关系
而且不需要额外的代码。