使用Django+DRF开发API时POST请求出现AttributeError问题求助
嘿,我看到你在用Django和DRF开发基础API时,POST请求碰到了棘手的500错误,咱们来一步步搞定它!
先揪出直接报错的原因
你在处理POST请求时写了data = JSONParser().parse(request.body),但DRF的JSONParser.parse()方法需要的是类文件流对象,而request.body是原生的bytes类型,根本没有read()方法——这就是你看到AttributeError: 'bytes' object has no attribute 'read'的核心原因。
不过其实还有几个小细节需要调整,咱们一起修正:
1. 丢掉手动解析,用DRF自带的request.data(最省心的方式)
既然用了DRF,它已经帮你封装好了请求解析、内容协商这些繁琐工作,完全不需要自己调用JSONParser。修改你的views.py代码:
from rest_framework.response import Response from rest_framework import status def user_list(request): """ List all code users, or create a new user. """ if request.method == 'GET': users = Users.objects.all() # 用默认的objects管理器更规范,除非你有自定义需求 serializer = UserSerializer(users, many=True) return Response(serializer.data) # DRF的Response会自动处理格式和状态码 elif request.method == 'POST': # 直接用request.data,DRF已经帮你解析好请求体了 serializer = UserSerializer(data=request.data) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
这里用DRF的Response替代Django原生的JsonResponse更符合REST API的规范,它会自动根据请求头返回合适的内容类型(比如JSON、XML等)。
2. 修复Serializer里的id字段问题
你的UserSerializer里把id定义成了普通的IntegerField,但Model里的id是自增主键(AutoField),创建用户时不需要客户端传入这个值,所以必须把它设为read_only=True,否则客户端不传id会触发校验错误:
class UserSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) # 标记为只读,创建时无需传入 name = serializers.CharField(max_length=200) # 和Model里的max_length保持一致,别用None email = serializers.CharField(max_length=200) position = serializers.CharField(max_length=15) def create(self, validated_data): # 用默认的objects管理器即可,除非你自定义了users管理器有特殊逻辑 return Users.objects.create(**validated_data) def update(self, instance, validated_data): # 更新时也不需要修改主键id,所以删掉这行赋值 instance.name = validated_data.get('name', instance.name) instance.email = validated_data.get('email', instance.email) instance.position = validated_data.get('position', instance.position) instance.save() return instance
另外,Serializer里的CharField建议和Model里的max_length保持一致,这样能提前拦截不符合长度要求的请求。
3. 优化Model的管理器(可选)
你的Users Model里显式定义了users = models.Manager(),其实Django默认会给每个Model生成objects管理器,如果你没有自定义管理器的特殊需求,完全可以删掉这行代码,直接用Users.objects.all()、Users.objects.create()等方法。
最后测试一下
修改完成后,用类似下面的JSON格式发送POST请求:
{ "name": "张三", "email": "zhangsan@example.com", "position": "developer" }
应该就能正常创建用户啦!
内容的提问来源于stack exchange,提问作者user12625513

