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

APIView的post方法无法将数据存入数据库问题求助

问题分析与修复方案

核心问题点

  1. 外键传值类型错误:request.data.get()拿到的是字符串格式的用户ID,但Follow模型的user和following_user是外键字段,需要传入User模型实例,直接传字符串会触发类型异常,导致数据无法写入数据库。
  2. 权限配置错误:DRF中权限配置属性是permission_classes(复数),你写的permission_class(单数)会导致权限验证不生效。
  3. 冗余无效代码:post方法内部嵌套的__str__方法完全无效,不会被执行。
  4. 不必要的save调用:Follow.objects.create()本身已经完成数据库写入,无需额外调用follow.save()。
  5. 安全隐患:从请求数据中获取user参数,可能被用户伪造(比如用自己的登录token却传别人的user ID),应该直接用当前登录用户request.user。
  6. 宽泛异常捕获:except:会吞掉所有异常,无法定位具体错误原因(比如用户不存在、重复关注等)。

修复后的代码

视图层(FollowingView)

from django.db import IntegrityError
from django.contrib.auth import get_user_model
from rest_framework import status, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Follow
from .serializers import FollowSerializer

User = get_user_model()

class FollowingView(APIView):
    permission_classes = [permissions.IsAuthenticated]  # 修正为复数形式

    def post(self, request):
        following_user_id = request.data.get('to_user')
        if not following_user_id:
            return Response({"error": "缺少必填参数to_user"}, status=status.HTTP_400_BAD_REQUEST)
        
        try:
            # 将ID转换为User实例
            following_user = User.objects.get(id=following_user_id)
            # 用当前登录用户作为关注主体,避免伪造
            follow, created = Follow.objects.get_or_create(
                user=request.user, 
                following_user=following_user
            )
            if not created:
                return Response({"error": "已关注该用户"}, status=status.HTTP_400_BAD_REQUEST)
            
            serializer = FollowSerializer(follow)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        
        except User.DoesNotExist:
            return Response({"error": "目标用户不存在"}, status=status.HTTP_404_NOT_FOUND)
        except IntegrityError:
            return Response({"error": "关注关系已存在"}, status=status.HTTP_400_BAD_REQUEST)

可选优化:序列化器(FollowSerializer)

如果不想返回完整的User对象,可以将外键字段序列化为用户名或ID,更符合接口返回规范:

from rest_framework import serializers
from .models import Follow

class FollowSerializer(serializers.ModelSerializer):
    user = serializers.CharField(source='user.username')
    following_user = serializers.CharField(source='following_user.username')

    class Meta:
        model = Follow
        fields = ['user', 'following_user', 'date_followed']

关键修复说明

  • 用request.user获取当前登录用户,确保关注主体的合法性,避免参数伪造。
  • 使用get_or_create替代create,既避免重复创建关注关系,也能处理模型的唯一约束。
  • 捕获具体异常(User.DoesNotExist、IntegrityError),返回明确的错误信息,方便调试和前端处理。
  • 将请求中的用户ID转换为User实例,满足外键字段的类型要求。

内容的提问来源于stack exchange,提问作者jdez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:40:43