如何使用Django模型制作跟随者跟踪系统

我是一个学习Django rest框架的学生

我正在用Django rest框架制作一个简单的sns

我需要关注者追踪系统。所以,我尝试做到了,但是有麻烦

首先,这是我的AbstractBaseUser和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)

现场追随者是跟随我的人,跟随者是我追随的人

当我使用此APIView类添加以下内容时

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)})

user_id是我,关注者是我想要关注的人

我想在user_id的关注者字段中添加关注,并在user_id的关注者字段中添加user_id

但这不起作用

我想要的结果是这样的(带有用户信息api)

{
        "followers": [],"following": [
            "some user"
        ],}

某些用户的用户信息

{
        "followers": [
            "user above"
        ],"following": [
        ],}

但是实际结果是这样的

{      
        "followers": [
            "some user"
        ],"following": [
            "user above"
        ],}

这不是我想要的

我不知道这个问题,我需要一些帮助

谢谢

shuangzai520 回答:如何使用Django模型制作跟随者跟踪系统

我会以不同的方式设计它。

我不会将信息添加到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 中反映的关系

而且不需要额外的代码。

本文链接:https://www.f2er.com/3126904.html

大家都在问