为模型表单额外字段指定小部件(Django)

27

我需要在我的模型表单中添加额外的字段。我的方法是:

class MyForm(forms.ModelForm):
    extra_field = forms.CharField()
    class Meta:
        model = MyModel
        widgets = {
            #Does not work
            'extra_field': forms.Textarea(attrs={'placeholder': u'Bla bla'}),
        }

但是看起来在 class Meta 中为 extra_field 定义的小部件被忽略了,因为我在模板中只有一个裸的 input 标签而不是 textarea

所以我采用了下面的方法:

class MyForm(forms.ModelForm):
    #It works fine
    extra_field = forms.CharField(widget=forms.Textarea())
    class Meta:
        model = MyModel

对我来说它完美地工作了,但我曾在 class Meta 声明中为表单字段指定了小部件。所以我想知道:

为什么我的第一种方法不起作用?我做错了什么?


你确定你正在使用Django 1.4吗?Form.Meta.widgets是在Django 1.4中引入的。 - jpic
2个回答

34

即使是额外的字段也没关系。这样做可以:

class FooForm(forms.ModelForm):
    class Meta:
        model = People
        widgets = { 
            'name': forms.Textarea(attrs={'placeholder': u'Bla bla'}),
        }   

这个不行:

class FooForm(forms.ModelForm):
    name = forms.CharField()

    class Meta:
        model = People
        widgets = { 
            'name': forms.Textarea(attrs={'placeholder': u'Bla bla'}),
        }

这是确实未记录的内容,这可能与该行为相关(也可能不相关),这是我在文档中找到的最佳匹配:

如果您明确地实例化一个表单字段,Django会认为您想要完全定义它的行为 [...] 您必须在声明表单字段时显式设置相关参数

该行为的实现在django/forms/models.py的219行。
   204         if opts.model:
   205             # If a model is defined, extract form fields from it.
   206             fields = fields_for_model(opts.model, opts.fields,
   207                                       opts.exclude, opts.widgets, formfield_callback)
   208             # make sure opts.fields doesn't specify an invalid field
   209             none_model_fields = [k for k, v in fields.iteritems() if not v]
   210             missing_fields = set(none_model_fields) - \
EE 211                              set(declared_fields.keys())
   212             if missing_fields:
   213                 message = 'Unknown field(s) (%s) specified for %s'
   214                 message = message % (', '.join(missing_fields),
   215                                      opts.model.__name__)
   216                 raise FieldError(message)
   217             # Override default model fields with any custom declared ones
   218             # (plus, include all the other declared fields).
   219             fields.update(declared_fields)

在第206行之后,fields['name'].widget确实是在Meta.widgets中指定的Textarea。
在第219行,fields通过declared_fields进行更新,fields['name'].widget变成了django.forms.widgets.TextInput,这是CharField的默认值。
显然,显式字段定义具有优先权。
谢谢提问,很高兴知道,好问题。

这个答案对我没用。也许 Django 改变了行为。 - Marshall X
这个仍然应该可以工作,也许再提一个问题? - jpic
我们可以在views.py中做这个吗? - Lord-shiv

4
我使用以下方法解决了上述问题:
class FooForm(forms.ModelForm):
    name = forms.CharField(widget=TextArea(attrs={'placeholder': u'Bla bla'}))
    class Meta:
        model = People

这会将字段名称添加到表中吗? - hlkstuv_23900

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接