在stackoverflow上看到一个问题,正好是我疑惑很久的相关问题。
[原问题地址]https://stackoverflow.com/questions/18265023/self-instance-in-django-modelform
What does self.instance in Django ModelForm constructor mean and where can I find a documentation about it?
class MyModelForm(ModelForm):
def __init__(self, *args, **kwargs):
super(MyModelForm, self).__init__(*args, **kwargs)
if self.instance:
...
下面有大神回答:
In a ModelForm, self.instance is derived from the model attribute specified in the Meta class. Your self in this context is obviously an instance of your subclass of ModelForm, and self.instance is (and will be on saving the form without errors) an instance of the model class you specified, although you have not done so in your example.
Accessing self.instance in init may not work, though doing so after calling the parent's init probably will. Further, I wouldn't recommend trying to change the instance directly. If you are interested, have a look at the BaseModelForm code on Github. The instance can also be specified when creating a new form via the instance argument.
This is not a generic Python thing. This is something that's defined specifically by ModelForm, in the superclass init
大致意思是:在modelform中,self.instance来源于元类中指定的model属性。你的self明显是这个上下文中ModelForm子类的实例化,而self.instance是(将在没有错误的情况下保存在表单中)你指定的model类的一个实例。尽管你在示例中没有这么做。
直接在__init__中访问self.instance也许不会工作,虽然在调用父类的__init__后可能会生效。此外,我不建议直接更改实例。如果您感兴趣,请查看Github上的BaseModelForm代码。在通过实例参数创建新表单时也可以指定实例。
最后总结下:self.instance不是python中通用的方法,这是以ModelForm形式,在超类的__init__中特别定义的方法。
另一个回答:
You can find the documentation on django's website.
https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-clean-method
Just search the page for every reference to "instance", and you should find what you need.
# Load up an instance
my_poll = Poll.objects.get(id=1)
# Declare a ModelForm with the instance
my_form = PollForm(request.POST, instance=my_poll)
# save() will return the model_form.instance attr which is the same as the model passed in
my_form.save() == my_poll == my_form.instance
他提到的是官方文档中关于instance例子,直接看官方的案例,我们可以找到我们问题的答案。
一共有三步,获取并加载一个对象实例,声明一个ModelForm的实例化,save()方法会返回model_form。实例属性与传入的model类型相同。
按照我的理解,这两个回答都指明了self.instance是modelform对象的实例化,包含了对象中的内容,我们可以通过self.instance访问并获取到对象的数据进行操作。关键在于,理清所实例化的对象在代码架构中的来龙去脉。
Fields are single data points, forms are a collection of fields.
思考题:想想为什么在django中form验证要设置clean()方法,它被设计出来的目的是什么?想要实现什么样的效果,在我们的代码结构中应该置于什么样的地位呢?
附录:
1.在django文档中,Model instance reference这部分提到Model.full_clean(exclude=None, validate_unique=True)。
There are three steps involved in validating a model:
- 验证模型字段 - Model.clean_fields()
- 验证模型作为一个整体 - Model.clean()
- 验证字段唯一性 - Model.validate_unique()
All three steps are performed when you call a model's ~Model.full_clean() method。而在我们使用ModelForm时,对 is_valid() 的调用将对表单上包含的所有字段执行这些验证步骤。
在文档的Form and field validation部分也重新讲解了clean()以及full_clean()方法,这是表单验证中最重要的部分!
2.在django文档中,提到了Model.pk属性。
粗略记录下:
For convenience, each model has an ~django.db.models.AutoField named id by default unless you explicitly specify primary_key=True on a field in your model. See the documentation for ~django.db.models.AutoField for more details.
为了方便起见,每个模型都默认有一个名为 id 的 AutoField,除非n你在模型中的字段上明确指定了 primary_key=True。
Regardless of whether you define a primary key field yourself, or let Django supply one for you, each model will have a property called pk. It behaves like a normal attribute on the model, but is actually an alias for whichever attribute is the primary key field for the model. You can read and set this value, just as you would for any other attribute, and it will update the correct field in the model.
无论是自定义主键字段还是django给你提供的,每个model都有一个名为PK 的属性。它是用于model主键字段的别名。你可以像对待其他字段属性一样,读取或设置值,它将更新模型中的正确字段。
3.文档中还提及,防止后台URL硬编码,我们最好在模板中使用 get_absolute_url()
You should avoid building the URL from unvalidated user input, in order to reduce possibilities of link or redirect poisoning::
def get_absolute_url(self):
return '/%s/' % self.name
If self.name is '/example.com' this returns '//example.com/' which, in turn, is a valid schema relative URL but not the expected '/%2Fexample.com/'.
下面是官方文档中列出的两个示例:
<!-- BAD template code. Avoid! -->
<a href="/people/{{ object.id }}/">{{ object.name }}</a> -------bad
<a href="{{ object.get_absolute_url }}">{{ object.name }}</a> ---------good
这里的逻辑是,如果你更改对象的URL结构,即使是一些简单的,如更正拼写错误,您也不想跟踪每个可能创建的URL的地方。所以可以在 get_absolute_url() 中指定一次,并让所有其他代码调用一个地方。
4.在文档的Overriding the clean() method该部分中,提到:
You can override the clean() method on a model form to provide additional validation in the same way you can on a normal form.A model form instance attached to a model object will contain an instance attribute that gives its methods access to that specific model instance.
大意是,您可以在模型表单上覆盖 clean() 方法,用与正常表单上相同的方式实现自定义验证。附加到模型对象的模型表单实例将包含一个 instance 属性,该方法为其提供访问该特定model的实例。