Django DRF:如何通过ModelSerializer接收模型外的用户额外字段并完成自定义数据写入
解决ModelSerializer添加额外字段导致创建用户时的参数错误问题
这个问题我之前也碰到过,本质是ModelSerializer默认会把所有在fields里的字段都传递给模型的构造方法,但roles并不是你的User模型的字段,所以才会抛出这个unexpected keyword argument 'roles'的错误。下面是具体的解决步骤和修正后的代码:
1. 调整Serializer的字段配置
首先要修正roles字段的属性:
- 把
roles标记为write_only=True,这样它只会接受用户输入,不会在序列化输出时返回,同时避免ModelSerializer把它传给模型构造函数 - 从
read_only_fields中移除roles(你之前的配置里把它设为只读,但又需要用户传入,这是矛盾的)
2. 重写Serializer的create方法
在创建User实例之后,手动处理roles字段,将对应的角色(AuthGroup)关联到用户的groups关系中(因为auth_user_groups是Django用户和组的中间表,你的User模型继承了PermissionsMixin,已经自带groups多对多字段)。
修正后的Serializer代码
from django.contrib.auth.models import Group from rest_framework import serializers from .models import User from .constants import constants from .enums import AuthGroup # 假设你的AuthGroup枚举在这里 class UserCreateSerializer(serializers.ModelSerializer): """ Serializer to create new user """ roles = serializers.MultipleChoiceField( choices=[(e.name, e.value) for e in AuthGroup], write_only=True # 关键:标记为只写字段 ) class Meta: model = User fields = ["name", "email", "is_active", "roles"] # 移除read_only_fields里的roles,因为我们需要用户传入这个字段 def validate_roles(self, value): if not value: raise serializers.ValidationError(detail=constants.NAMED_FIELD_REQUIRED.format(field="roles")) return value def create(self, validated_data): # 先从validated_data中移除roles字段,避免传给User构造函数 roles = validated_data.pop('roles') # 创建用户实例 user = User.objects.create(**validated_data) # 根据传入的角色名称,获取对应的Group对象 groups = Group.objects.filter(name__in=roles) # 将用户添加到这些组中,自动在auth_user_groups表创建关联 user.groups.add(*groups) return user
关键改动说明
- write_only=True:告诉Serializer这个字段只用于接收输入,不会包含在输出的序列化数据里,同时ModelSerializer在调用模型构造函数时会自动忽略这个字段
- pop('roles'):在创建用户前,先从验证后的数据中移除
roles,这样User.objects.create()就不会收到这个多余的参数 - user.groups.add(*groups):利用Django自带的多对多关系方法,批量将用户添加到对应的组中,这会自动在
auth_user_groups表中生成关联条目
测试验证
当你传入你提供的请求体时:
{ "name": "test4", "email": "test4@example.com", "is_active": true, "roles": [ "ADMIN", "OPERATOR" ] }
现在Serializer会先验证roles字段,然后创建用户,最后将用户关联到ADMIN和OPERATOR对应的组,不会再抛出参数错误。
内容的提问来源于stack exchange,提问作者Ropali Munshi
相关产品推荐
相关产品推荐

