Specifying widget for model form extra field (Django)

末鹿安然 提交于 2019-11-28 08:10:22

It doesn't matter if it's an extra field. This works:

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

This doesn't:

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

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

This is not documented indeed, that's the best I could find in the docs that could relate to that behaviour (maybe it doesn't, it's just the best i could find):

If you explicitly instantiate a form field like this, Django assumes that you want to completely define its behavior [...] you must set the relevant arguments explicitly when declaring the form field.

The implementation of this behaviour is in django/forms/models.py line 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)

After line 206, fields['name'].widget is indeed the Textarea specified in Meta.widgets.

At line 219, fields is updated with declared_fields, and fields['name'].widget becomes django.forms.widgets.TextInput which is the default for CharField.

Apparently, explicit field definitions have priority.

Thanks for asking, good to know, great question.

I solved the situation above with the following:

class FooForm(forms.ModelForm):
    name = forms.CharField(widget=TextArea(attrs={'placeholder': u'Bla bla'}))
    class Meta:
        model = People
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!