Django DRF:使用序列化器从用户那里获取额外输入但不存在于模型中
Django DRF: Take extra input from user using serializer but not present in the model
我有一个 ModelSerializer
class 用于用户输入和验证。我将它与 ModelViewset 一起使用,它使用序列化程序自动在数据库中创建一个新条目。现在我想做的是我想在序列化程序中有一个额外的字段,比如 roles
,这将由用户提供。它是一个用户角色数组,但该字段不存在于模型中,我想在 auth_user_groups
table 中手动添加此角色条目。所以我这样写了我的序列化器,
class UserCreateSerializer(serializers.ModelSerializer):
"""
Serializer to create new user
"""
class Meta:
model = User
fields = ["name", "email", "is_active", "roles"]
read_only_fields = ['roles']
roles = serializers.MultipleChoiceField(choices=[(e.name,e.value) for e in AuthGroup])
def validate_roles(self, value):
if not value:
raise ValidationError(detail=constants.NAMED_FIELD_REQUIRED.format(field="roles"))
我的模型是这样的,
class User(AbstractBaseUser, PermissionsMixin):
class Meta:
db_table = "auth_user"
app_label = "users"
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
name = models.CharField(max_length=255, null=True)
email = models.EmailField("email address", unique=True, null=True)
is_active = models.BooleanField(default=True)
is_superuser = None
is_admin = None
is_verified = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = UserManager()
def __str__(self):
return self.name or self.email
def is_admin(self):
return self.groups.filter(name=AuthGroup.ADMIN.name).exists()
这是来自用户的请求正文。
{
"name": "test4",
"email": "test4@example.com",
"is_active": true,
"roles": [
"ADMIN", "OPERATOR"
]
}
所以每当我尝试调用 API,
raise TypeError("%s() got an unexpected keyword argument '%s'" %
(cls.name, kwarg)) TypeError: User() got an unexpected keyword
argument 'roles'
所以有人知道我该如何解决这个问题或实现我上面所说的吗?任何帮助将不胜感激...
这是因为经过验证的数据正在序列化程序的 create(...)
方法中传递给 QuerySet
的 create(...)
方法。所以,你需要在创建操作之前弹出roles
字段。
class UserCreateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["name", "email", "is_active", "roles"]
roles = serializers.MultipleChoiceField(
choices=[(e.name, e.value) for e in AuthGroup],
required=True,
write_only=True
)
def validate_roles(self, value):
# do some validations
return value
<b>def create(self, validated_data):
roles = validated_data.pop("roles", None)
return super().create(validated_data)</b>
备注
- 您可以使用
required=True
将该字段设置为必填字段,这样您就不必为此进行任何额外的验证
read_only_fields
将适用于 未 在序列化程序中明确定义的那些字段。
我有一个 ModelSerializer
class 用于用户输入和验证。我将它与 ModelViewset 一起使用,它使用序列化程序自动在数据库中创建一个新条目。现在我想做的是我想在序列化程序中有一个额外的字段,比如 roles
,这将由用户提供。它是一个用户角色数组,但该字段不存在于模型中,我想在 auth_user_groups
table 中手动添加此角色条目。所以我这样写了我的序列化器,
class UserCreateSerializer(serializers.ModelSerializer):
"""
Serializer to create new user
"""
class Meta:
model = User
fields = ["name", "email", "is_active", "roles"]
read_only_fields = ['roles']
roles = serializers.MultipleChoiceField(choices=[(e.name,e.value) for e in AuthGroup])
def validate_roles(self, value):
if not value:
raise ValidationError(detail=constants.NAMED_FIELD_REQUIRED.format(field="roles"))
我的模型是这样的,
class User(AbstractBaseUser, PermissionsMixin):
class Meta:
db_table = "auth_user"
app_label = "users"
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
name = models.CharField(max_length=255, null=True)
email = models.EmailField("email address", unique=True, null=True)
is_active = models.BooleanField(default=True)
is_superuser = None
is_admin = None
is_verified = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = UserManager()
def __str__(self):
return self.name or self.email
def is_admin(self):
return self.groups.filter(name=AuthGroup.ADMIN.name).exists()
这是来自用户的请求正文。
{
"name": "test4",
"email": "test4@example.com",
"is_active": true,
"roles": [
"ADMIN", "OPERATOR"
]
}
所以每当我尝试调用 API,
raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.name, kwarg)) TypeError: User() got an unexpected keyword argument 'roles'
所以有人知道我该如何解决这个问题或实现我上面所说的吗?任何帮助将不胜感激...
这是因为经过验证的数据正在序列化程序的 create(...)
方法中传递给 QuerySet
的 create(...)
方法。所以,你需要在创建操作之前弹出roles
字段。
class UserCreateSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["name", "email", "is_active", "roles"]
roles = serializers.MultipleChoiceField(
choices=[(e.name, e.value) for e in AuthGroup],
required=True,
write_only=True
)
def validate_roles(self, value):
# do some validations
return value
<b>def create(self, validated_data):
roles = validated_data.pop("roles", None)
return super().create(validated_data)</b>
备注
- 您可以使用
required=True
将该字段设置为必填字段,这样您就不必为此进行任何额外的验证 read_only_fields
将适用于 未 在序列化程序中明确定义的那些字段。