Django REST Framework 中序列化程序验证的顺序 [英] Order of Serializer Validation in Django REST Framework
问题描述
情况
在 Django REST Framework 的 ModelSerializer
中使用验证时,我注意到 Meta.model
字段总是经过验证,即使它不一定有意义这样做.以User
模型的序列化为例:
While working with validation in the Django REST Framework's ModelSerializer
, I have noticed that the Meta.model
fields are always validated, even when it does not necessarily make sense to do so. Take the following example for a User
model's serialization:
- 我有一个创建用户的端点.因此,有一个
password
字段和一个confirm_password
字段.如果两个字段不匹配,则无法创建用户.同样,如果请求的username
已经存在,则无法创建用户. - 用户为上述每个字段发布了不正确的值
- 在序列化程序中实现了
validate
(见下文),捕获不匹配的password
和confirm_password
字段莉>
- I have an endpoint that creates a user. As such, there is a
password
field and aconfirm_password
field. If the two fields do not match, the user cannot be created. Likewise, if the requestedusername
already exists, the user cannot be created. - The user POSTs improper values for each of the fields mentioned above
- An implementation of
validate
has been made in the serializer (see below), catching the non-matchingpassword
andconfirm_password
fields
validate
的实现:
def validate(self, data):
if data['password'] != data.pop('confirm_password'):
raise serializers.ValidationError("Passwords do not match")
return data
问题
即使 ValidationError
由 validate
引发,ModelSerializer
仍会查询数据库以检查 username
已在使用中.这在从端点返回的错误列表中很明显;模型误差和非现场误差都存在.
Even when the ValidationError
is raised by validate
, the ModelSerializer
still queries the database to check to see if the username
is already in use. This is evident in the error-list that gets returned from the endpoint; both the model and non-field errors are present.
因此,我想知道如何在非字段验证完成之前阻止模型验证,从而节省了对数据库的调用.
Consequently, I would like to know how to prevent model validation until after non-field validation has finished, saving me a call to my database.
尝试解决
我一直试图通过 DRF 的来源找出发生这种情况的地方,但我一直未能找到我需要覆盖的内容才能使其正常工作.
I have been trying to go through the DRF's source to figure out where this is happening, but I have been unsuccessful in locating what I need to override in order to get this to work.
推荐答案
因为很可能你的 username
字段设置了 unique=True
,Django REST Framework 会自动添加一个验证器检查以确保新用户名是唯一的.您实际上可以通过执行 repr(serializer())
来确认这一点,这将向您显示所有自动生成的字段,其中包括验证器.
Since most likely your username
field has unique=True
set, Django REST Framework automatically adds a validator that checks to make sure the new username is unique. You can actually confirm this by doing repr(serializer())
, which will show you all of the automatically generated fields, which includes the validators.
验证以特定的、未记录的顺序运行
- 字段反序列化调用 (
和field.run_validators
) serializer]
[ 为每个字段调用- 调用序列化程序级验证器 (
后跟 serializer
) serializer.validate
> 被称为
- Field deserialization called (
serializer.to_internal_value
andfield.run_validators
) serializer.validate_[field]
is called for each field- Serializer-level validators are called (
serializer.run_validation
followed byserializer.run_validators
) serializer.validate
is called
因此,您看到的问题是在序列化程序级验证之前调用了字段级验证.虽然我不推荐它,但您可以通过在序列化器的元数据中设置 extra_kwargs
来删除字段级验证器.
So the problem that you are seeing is that the field-level validation is called before your serializer-level validation. While I wouldn't recommend it, you can remove the field-level validator by setting extra_kwargs
in your serilalizer's meta.
class Meta:
extra_kwargs = {
"username": {
"validators": [],
},
}
不过,您需要在自己的验证中重新实现 unique
检查,以及自动生成的任何其他验证器.
You will need to re-implement the unique
check in your own validation though, along with any additional validators that have been automatically generated.
这篇关于Django REST Framework 中序列化程序验证的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!