在ModelForm中覆盖初始值
在我的Django(1.2)项目中,我想在一个模型表单里预先填充一个字段,但我新的值总是被忽略。以下是相关代码:
class ArtefactForm(ModelForm):
material = CharField(widget=AutoCompleteWidget('material', force_selection=False))
def __init__(self, *args, **kwargs):
super(ArtefactForm, self).__init__(*args, **kwargs)
self.fields['material'].initial = 'Test'
我也试过用 self.base_fields
,但是没有效果:表单里总是显示数据库里的值。有没有什么想法?
2 个回答
这个问题虽然老了,但我觉得加个详细的回答会对一些新开发者有帮助。
我也试过用
self
.base_fields
,但没效果:表单里总是显示数据库里的值。有什么想法吗?
如果一个表单是“初始化”的,可能有两种情况:
使用
initial
参数(比如YourModelFrom(initial={'filed1': variable})
— 通常在你想为某些字段传递动态计算的初始值时使用)。参考设置初始值
或者
使用
instance
参数(比如YourModelFrom(instance=model_object)
— 通常在你想更新一个已有的模型实例对象时使用)。参考save() 方法
注意:
1 `ModelFrom` 类继承自 `BaseModelFrom` 类。
2 当我们将模型类实例对象分配给instance
参数时(因此instance is not None
),`BaseModelFrom` 的构造函数会调用model_to_dict()
并在调用父类构造函数之前更新initial
参数。查看def __init__
在 BaseModelFrom 类中
然后,明确给字段赋初始值(就像问题中 OP 的代码那样)没有效果,这是因为 _clean_fields
方法在 BaseFrom
类中的写法。
代码片段:
def _clean_fields(self):
for name, field in self.fields.items():
value = field.widget.value_from_datadict(
self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.initial.get(name, field.initial) # <- Check
value = field.clean(value, initial)
else:
根据代码行 initial = self.initial.get(name, field.initial)
,如果在 initial
字典中给了字段的初始值,那么分配给 field.initial
的值将 不 被使用。
[回答]:
虽然 @Daniel 的回答是完全正确的,但还有另一种方法可以达到相同的效果,就是使用 self.initial
:
def __init__(self, *args, **kwargs):
super(ArtefactForm, self).__init__(*args, **kwargs)
self.initial['material'] = 'Test'
试试看吧!!
self.initial
其实就是我们传入的字典。查看代码 __init__
在 BaseForm
中:
class BaseForm(object):
def __init__(........
........):
:
self.prefix = prefix
self.initial = initial or {} # <-- Notice
self.error_class = error_class
:
注意:我没有找到关于使用 initial 属性的文档,我只是探索了基础代码并使用了它。
编辑:问题中报告的行为在 Django 模型中也有文档说明。
动态初始值
Form.initial
注意,如果一个
Field
定义了initial
,而你在实例化表单时也包含了initial
,那么后者的initial
将优先使用。在这个例子中,initial
在字段级别和表单实例级别都有提供,而后者优先:>>> from django import forms >>> class CommentForm(forms.Form): ... name = forms.CharField(initial='class') ... url = forms.URLField() ... comment = forms.CharField() >>> f = CommentForm(initial={'name': 'instance'}, auto_id=False) >>> print(f) <tr><th>Name:</th><td><input type="text" name="name" value="instance" /> <tr><th>Url:</th><td><input type="url" name="url" /></td></tr> <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
PS:顺便说一下,我回答中的第 2 点说明了 initial
和 instance
参数之间的区别。还有一个关键的键值参数 data
- 这个值会触发表单验证。阅读这个 Django 表单 'initial' 和 '绑定数据' 的区别?。
试试这个:
def __init__(self, *args, **kwargs):
initial = kwargs.get('initial', {})
initial['material'] = 'Test'
kwargs['initial'] = initial
super(ArtefactForm, self).__init__(*args, **kwargs)