You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django REST Framework博客应用关注系统实现故障排查求助

Hey there! Let's walk through the issues in your code and fix them step by step. I see two main problems: incorrect follower/following data showing up in your user API, and broken follow/unfollow endpoints. Let's tackle them one by one.


1. Fixing Follower/Following Serialization

Right now, your UserSerializer is returning data from the UserFollowing join table instead of the actual users you're following or who follow you. Plus, the way you've defined the fields is preventing DRF from using your custom get_following/get_followers methods.

Here's a corrected version that either returns linked user URLs (simple) or nested user data with follow timestamps (more detailed):

Option 1: Simple Linked User List

class UserSerializer(serializers.HyperlinkedModelSerializer):
    # Directly point to the related User objects in the join table
    following = serializers.HyperlinkedRelatedField(
        many=True, 
        view_name='user-detail', 
        read_only=True,
        source='following.following_user_id'
    )
    followers = serializers.HyperlinkedRelatedField(
        many=True, 
        view_name='user-detail', 
        read_only=True,
        source='followers.user_id'
    )
    posts = serializers.HyperlinkedRelatedField(many=True, view_name='post-detail', read_only=True)

    class Meta:
        model = User
        fields = ['url', 'id', 'username', 'posts', 'following', 'followers']

Option 2: Nested Data with Follow Timestamps

If you want to include when the follow relationship was created, use this version:

class UserSerializer(serializers.HyperlinkedModelSerializer):
    following = serializers.SerializerMethodField()
    followers = serializers.SerializerMethodField()
    posts = serializers.HyperlinkedRelatedField(many=True, view_name='post-detail', read_only=True)

    class Meta:
        model = User
        fields = ['url', 'id', 'username', 'posts', 'following', 'followers']

    def get_following(self, obj):
        # Serialize followed users + follow timestamp
        return [{
            'user': UserSerializer(entry.following_user_id, context=self.context).data,
            'followed_at': entry.created
        } for entry in obj.following.all()]

    def get_followers(self, obj):
        # Serialize followers + follow timestamp
        return [{
            'user': UserSerializer(entry.user_id, context=self.context).data,
            'followed_at': entry.created
        } for entry in obj.followers.all()]

2. Fixing Follow/Unfollow Endpoints

Your current endpoints have two critical issues: passing user IDs instead of User instances to the foreign key fields, and using delete() incorrectly (which would delete all follow relationships instead of just the one for the current user). Here's the fixed version:

from rest_framework import status
from django.db import IntegrityError

class UserFollow(APIView):
    """ Follow or unfollow a user """
    def get_object(self, pk):
        try:
            return User.objects.get(pk=pk)
        except User.DoesNotExist:
            raise Http404

    def post(self, request, pk, format=None):
        current_user = request.user
        user_to_follow = self.get_object(pk)

        # Prevent self-follows
        if current_user == user_to_follow:
            return Response({"error": "You can't follow yourself"}, status=status.HTTP_400_BAD_REQUEST)

        # Create follow relationship (unique constraint handles duplicates)
        try:
            UserFollowing.objects.create(user_id=current_user, following_user_id=user_to_follow)
        except IntegrityError:
            return Response({"error": "You already follow this user"}, status=status.HTTP_400_BAD_REQUEST)

        # Return current user's updated data
        serializer = UserSerializer(current_user, context={'request': request})
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def delete(self, request, pk, format=None):
        current_user = request.user
        user_to_unfollow = self.get_object(pk)

        # Delete the specific follow relationship
        deleted_count, _ = UserFollowing.objects.filter(
            user_id=current_user, 
            following_user_id=user_to_unfollow
        ).delete()

        if deleted_count == 0:
            return Response({"error": "You don't follow this user"}, status=status.HTTP_404_NOT_FOUND)

        # Return current user's updated data
        serializer = UserSerializer(current_user, context={'request': request})
        return Response(serializer.data, status=status.HTTP_200_OK)

3. Small Model Optimization

Your UserFollowing model uses on_delete=models.SET_NULL, which leaves orphaned entries if a user is deleted. Change it to CASCADE to clean up follow relationships automatically:

class UserFollowing(models.Model):
    class Meta:
        constraints= [
            models.UniqueConstraint(fields=['user_id', 'following_user_id'], name='unique_following')
        ]
        ordering = ['-created']
    user_id = models.ForeignKey('auth.User', related_name='following', on_delete=models.CASCADE)
    following_user_id = models.ForeignKey('auth.User', related_name='followers', on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'{self.user_id} is following {self.following_user_id}'

With these changes, your API will:

  • Show the correct list of followed users and followers
  • Allow users to follow/unfollow others without errors
  • Handle edge cases like self-follows and duplicate follow attempts
  • Clean up orphaned follow relationships when users are deleted

内容的提问来源于stack exchange,提问作者Роман Беляев

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:52:36