如何使用django模型制作跟随系统

Hye*_*eok 12 django django-models django-rest-framework

我是一名学习 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)
Run Code Online (Sandbox Code Playgroud)

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

当我使用此 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)})
Run Code Online (Sandbox Code Playgroud)

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

我想将关注添加到 user_id 的关注字段并将 user_id 添加到关注的关注字段

但它不起作用

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

{
        "followers": [],
        "following": [
            "some user"
        ],
}
Run Code Online (Sandbox Code Playgroud)

一些用户的用户信息

{
        "followers": [
            "user above"
        ],
        "following": [
        ],
}
Run Code Online (Sandbox Code Playgroud)

但真正的结果是这样的

{      
        "followers": [
            "some user"
        ],
        "following": [
            "some user"
        ],
}
Run Code Online (Sandbox Code Playgroud)

一些用户的用户信息

{
        "followers": [
            "user above"
        ],
        "following": [
            "user above"
        ],
}
Run Code Online (Sandbox Code Playgroud)

这不是我想要的

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

谢谢

Ent*_*tin 23

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

我不会将信息添加到User模型中,而是明确创建另一个表来存储有关“关注者”和“关注者”的信息。

表的架构将是:

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)
Run Code Online (Sandbox Code Playgroud)

现在,在您的 post 方法实现中,您只需执行以下操作:

UserFollowing.objects.create(user_id=user.id,
                             following_user_id=follow.id)
Run Code Online (Sandbox Code Playgroud)

然后,您可以轻松访问以下和关注者:

user = User.objects.get(id=1) # it is just example with id 1
user.following.all()
user.followers.all()
Run Code Online (Sandbox Code Playgroud)

然后您可以创建约束,这样用户就不能两次关注同一个用户。但我把这留给你(提示:unique_together)

  • 哇!!它工作成功。谢谢!!我根据你的提示阻止关注同一用户两次。谢谢你的好心。 (2认同)

uni*_*dev 13

上述解决方案很好,而且是最佳的,但我想为任何想要实现此类功能的人提供详细的解决方案。

中介模式

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

Run Code Online (Sandbox Code Playgroud)

用于关注和取消关注的序列化程序

您关注和取消关注的视图

class UserFollowingViewSet(viewsets.ModelViewSet):

    permission_classes = (IsAuthenticatedOrReadOnly,)
    serializer_class = UserFollowingSerializer
    queryset = models.UserFollowing.objects.all()
Run Code Online (Sandbox Code Playgroud)

自定义 FollowersSerializer 和 FollowersSerializer

class FollowingSerializer(serializers.ModelSerializer):

    class Meta:
        model = UserFollowing
        fields = ("id", "following_user_id", "created")
Run Code Online (Sandbox Code Playgroud)
class FollowersSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserFollowing
        fields = ("id", "user_id", "created")
Run Code Online (Sandbox Code Playgroud)

你的用户序列化器

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
Run Code Online (Sandbox Code Playgroud)


小智 5

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()
Run Code Online (Sandbox Code Playgroud)