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,提问作者Роман Беляев

