这是一个示例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(...) # irrelevant here
foo = models.ForeignKey(Foo, validators=[my_validator])
如果我创建了一个Foo实例,然后是一个Bar实例(分配foo实例),然后验证,则此代码通过:要验证的FK值不是模型实例而是ID(默认为整数) ):
foo = Foo.objects.create(name='foo')
bar = Bar.objects.create(name='bar', foo=foo)
修改:我忘记加入full_clean()
来电。但是是的:麻烦的代码调用full_clean()
。事实上,我第一次注意到这种行为是在尝试将验证器中的value
可调用时,作为模型实例而不是原始值,在尝试调用实例时触发了int value has no attribute xxx
验证器内部的方法。
bar.full_clean()
这在Django 1.9中发生。这是记录和预期的吗?
答案 0 :(得分:3)
是的 - ForeignKey.to_field
的文档中隐含地提到了这一点:
关系所涉及的相关对象上的字段。默认情况下,Django使用相关对象的主键。
此外:
对于映射到模型实例的
ForeignKey
等字段,默认值应该是它们引用的字段的值(pk
,除非设置了to_field
)而不是模型实例。
也就是说,默认情况下,value
的{{1}}是相关对象的主键 - 即整数。
但是,您可以指定其他ForeignKey
,在这种情况下,to_field
将采用该字段的类型。
就传递给验证器的值而言,似乎隐含的假设是value
(除了将要存储在数据库中的值之外,您还要验证什么?在验证外键时传递模型对象没有多大意义,因为键本身只是指向对象的指针,并没有说明该对象应该是什么。)。
但要回答你的问题 - 似乎没有任何明确的文件说明这一点。
答案 1 :(得分:1)
我不确定@ solarissmoke 答案是否与问题相关。
IMO,objects.create
未在ModelForm
调用,如果您想在创建模型之前验证模型,则应使用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_fields
好的,那么究竟发生了什么,当你致电validation时,我们会调用.full_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
内,我们有类似的内容:
raw_value
发生两件事:
field.clean
字段field.clean()
在validate()
我们按此顺序调用了.clean_fields(),.run_validators()
和value = self.to_python(value)
self.validate(value)
self.run_validators(value)
return value
,其内容如下:
int/long
Django在这里解释:.to_python()
但是,这不是您在自定义validator
中获得ForeignKey
的原因。
原因是因为_id
字段Form and field validation位于结尾有f.attname
的属性中,等于FKs
。因此,在验证int/long
的整个过程中,Django使用exists
值,而不是使用对象。
如果您看到store their values方法,则会发现它只会检查具有该ID Disk Space Usage
的行。