Python 这种行为是否记录在Django';s外键的字段验证器?
这是Python 2代码的一个示例:Python 这种行为是否记录在Django';s外键的字段验证器?,python,django,Python,Django,这是Python 2代码的一个示例: from django.db import models def my_validator(value): assert isinstance(value, (int, long)) class Foo(models.Model): name = models.CharField(...) # irrelevant here class Bar(models.Model): name = models.CharField(...
from django.db import models
def my_validator(value):
assert isinstance(value, (int, long))
class Foo(models.Model):
name = models.CharField(...) # irrelevant here
class Bar(models.Model):
name = models.CharField(...) # irrelevant here
foo = models.ForeignKey(Foo, validators=[my_validator])
如果创建一个Foo实例,然后创建一个Bar实例(分配Foo实例),然后进行验证,则此代码会传递:要验证的FK值不是模型实例,而是一个ID(默认情况下为整数):
Edit:我忘了包含full\u clean()
调用。但是是的:麻烦的代码调用full\u clean()
。事实上,我第一次注意到这种行为是在尝试将validator callable中的值
视为模型实例而不是原始值时,这在尝试调用validator中的实例方法时触发了int value has no attribute xxx
bar.full_clean()
这发生在Django 1.9中。这是否已记录在案并符合要求?是-这在以下文件中被隐式提及: 相关对象上与该关系相关的字段。默认情况下,Django使用相关对象的主键 此外: 对于映射到模型实例的
ForeignKey
等字段,默认值应为它们引用的字段的值(pk
,除非设置了to_field
),而不是模型实例
也就是说,默认情况下,外键
的值
是相关对象的主键,即整数
但是,您可以指定不同的to_字段
,在这种情况下,值将采用该字段的类型
就传递给验证器的值而言,似乎假设这是to_字段
(除了要存储在数据库中的值之外,您还要验证什么?在验证外键时传递模型对象没有多大意义,因为该键本身只是指向该对象的指针,并且没有说明该对象应该是什么。)
但为了回答您的问题-似乎没有任何明确的文档说明这一点。是-文档中暗指这一点:
关系所指向的相关对象上的字段。默认情况下,Django使用相关对象的主键
此外:
对于映射到模型实例的ForeignKey
等字段,默认值应为它们引用的字段的值(pk
,除非设置了to_field
),而不是模型实例
也就是说,默认情况下,外键
的值
是相关对象的主键,即整数
但是,您可以指定不同的to_字段
,在这种情况下,值将采用该字段的类型
就传递给验证器的值而言,似乎假设这是to_字段
(除了要存储在数据库中的值之外,您还要验证什么?在验证外键时传递模型对象没有多大意义,因为该键本身只是指向该对象的指针,并且没有说明该对象应该是什么。)
但是要回答你的问题-似乎没有任何明确的文档说明这一点。我不确定@solarissmoke的答案是否与该问题相关
IMO不会在对象上调用。创建
,如果要在创建模型之前验证模型,应使用模型表单
,或手动调用它
foo = Foo.objects.create(name='foo')
bar = Bar(name='bar', foo=foo)
try:
bar.full_clean()
bar.save()
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
更新:
好的,那么确切的情况是,当你打电话给我们时,我们会接到电话
在clean_字段中
有如下内容:
raw_value = getattr(self, f.attname)
if f.blank and raw_value in f.empty_values:
continue
try:
setattr(self, f.attname, f.clean(raw_value, self))
except ValidationError as e:
errors[f.name] = e.error_list
value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
发生两件事:
我们得到字段的原始值
我们调用field.clean
在字段.clean()
中,我们有,validate()
和.run\u validators()
按以下顺序调用:
raw_value = getattr(self, f.attname)
if f.blank and raw_value in f.empty_values:
continue
try:
setattr(self, f.attname, f.clean(raw_value, self))
except ValidationError as e:
errors[f.name] = e.error_list
value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
Django在这里解释道:
但是,这不是在自定义的验证器中获得int/long
的原因
这是因为ForeignKey
属性中的字段末尾带有\u id
,等于f.attname
。因此,在验证FKs
Django的整个过程中,Django使用的是int/long
值,而不是对象
如果您看到该方法,您会发现它只是检查id为的行是否存在
我不确定@solarismoke答案是否与问题相关
IMO不会在对象上调用。创建
,如果要在创建模型之前验证模型,应使用模型表单
,或手动调用它
foo = Foo.objects.create(name='foo')
bar = Bar(name='bar', foo=foo)
try:
bar.full_clean()
bar.save()
except ValidationError as e:
# Do something based on the errors contained in e.message_dict.
# Display them to a user, or handle them programmatically.
pass
更新:
好的,那么确切的情况是,当你打电话给我们时,我们会接到电话
在clean_字段中
有如下内容:
raw_value = getattr(self, f.attname)
if f.blank and raw_value in f.empty_values:
continue
try:
setattr(self, f.attname, f.clean(raw_value, self))
except ValidationError as e:
errors[f.name] = e.error_list
value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
发生两件事:
我们得到字段的原始值
我们调用field.clean
在字段.clean()
中,我们有,validate()
和.run\u validators()
按以下顺序调用:
raw_value = getattr(self, f.attname)
if f.blank and raw_value in f.empty_values:
continue
try:
setattr(self, f.attname, f.clean(raw_value, self))
except ValidationError as e:
errors[f.name] = e.error_list
value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
Django在这里解释道:
但是,这不是在自定义的验证器中获得int/long
的原因
这是因为ForeignKey
属性中的字段末尾带有\u id
,等于f.attname
。因此,在验证FKs
Django的整个过程中,Django使用的是int/long
值,而不是对象
如果您看到该方法,您会发现它只是检查id为的行是否存在
对不起!我忘了包含完整的\u clean调用。但是是的,我调用了它。“Django使用int/long值,而不是对象。”…这