DRF中如何修改serializer create()方法关联嵌套已有用户对象
Django REST Framework 关联已存在用户创建群组问题修复
问题场景
应用中Group(群组)由User(用户)创建,预期逻辑为:创建Group对象时,仅允许将已存在的User设置为群组owner(所有者),关联通过和数据库主键id相互独立的user_id字段完成,但实际发送POST请求时持续触发校验报错。
原有实现代码
初始序列化器
class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["user_id", "username"] class GroupSerializer(serializers.ModelSerializer): owner = UserSerializer() class Meta: model = Group fields = ["name", "picture_url", "owner", "members"] def create(self, validated_data): owner_data = validated_data.pop("owner") user = User.objects.filter(user_id=owner_data.get("user_id")) instance = Group.objects.create(**validated_data) instance.owner = user instance.save return instance
视图POST方法
def post(self, request): new_group = request.data new_group["members"] = [] serializer = self.serializer_class(data=new_group) serializer.is_valid(raise_exception=True) serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED)
模型定义
class User(models.Model): id = models.BigAutoField(primary_key=True, unique=True) user_id = models.BigIntegerField(unique=True) username = models.CharField(max_length=100) class Group(models.Model): name = models.CharField(max_length=255, unique=True) picture_url = models.CharField(max_length=255) owner = models.ForeignKey( User, on_delete=models.CASCADE, related_name="owned_groups", blank=True, ) members = models.ManyToManyField(User, related_name="groups", blank=True)
测试请求与报错
发送的POST请求体:
{ "owner": { "user_id":6 }, "picture_url":"nothing", "name":"jazz club" }
接口返回报错:
{ "owner": { "user_id": [ "user with this user id already exists." ], "username": [ "This field is required." ] } }
报错根因
- 嵌套的
UserSerializer默认走嵌套对象创建/更新逻辑,会对传入的user_id做全局唯一性校验,传入已存在的user_id时直接抛出「user id已存在」错误 - 嵌套的
UserSerializer默认要求fields列表内所有字段(user_id、username)为必传项,未传username时触发必填校验错误 - 原有
create方法存在两处代码bug:User.objects.filter()返回的是QuerySet集合,不是单个User实例,直接赋值给外键字段会触发类型错误instance.save未添加调用括号,实际不会执行数据库保存操作
修复方案
无需修改模型和视图代码,仅调整序列化器逻辑即可:
- 自定义关联字段,关闭嵌套序列化器的新建用户逻辑,仅校验传入的
user_id对应的用户是否存在 - 修复原有create方法的代码bug
- 保证返回数据格式和原有预期一致,返回owner完整信息而非仅用户ID
修改后的完整序列化器代码:
from rest_framework import serializers from .models import User, Group # 读取用户详情时使用,返回user_id和username class UserReadSerializer(serializers.ModelSerializer): class Meta: model = User fields = ["user_id", "username"] # 自定义owner关联字段:写入时接收user_id,校验对应用户是否存在;读取时返回完整用户信息 class ExistingUserByUserIdField(serializers.Field): def to_internal_value(self, data): # 写入逻辑:根据传入的user_id查找已存在的用户 try: return User.objects.get(user_id=data) except User.DoesNotExist: raise serializers.ValidationError("指定user_id对应的用户不存在") except (TypeError, ValueError): raise serializers.ValidationError("user_id必须为整数") def to_representation(self, value): # 读取逻辑:返回用户的完整序列化结果 return UserReadSerializer(value).data class GroupSerializer(serializers.ModelSerializer): owner = ExistingUserByUserIdField() class Meta: model = Group fields = ["name", "picture_url", "owner", "members"] def create(self, validated_data): # 校验通过后,validated_data中的owner已经是查询到的User实例,可直接创建 instance = Group.objects.create(**validated_data) # 初始化空成员列表 instance.members.set([]) return instance
效果验证
发送和之前完全一致的POST请求,可正常创建群组,返回结果格式符合预期:
{ "name": "jazz club", "picture_url": "nothing", "owner": { "user_id": 6, "username": "该user_id对应的实际用户名" }, "members": [] }
内容的提问来源于stack exchange,提问作者Niels Boelens
相关产品推荐
相关产品推荐

