=== modified file 'django/forms/models.py'
--- django/forms/models.py 2008-09-27 17:49:41 +0000
+++ django/forms/models.py 2008-09-28 23:01:22 +0000
@@ -123,7 +123,7 @@
data[f.name] = f.value_from_object(instance)
return data
-def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
+def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
"""
Returns a ``SortedDict`` containing form fields for the given model.
@@ -144,7 +144,11 @@
continue
if exclude and f.name in exclude:
continue
- formfield = formfield_callback(f)
+ if widgets and f.name in widgets:
+ kwargs = {'widget': widgets[f.name]}
+ else:
+ kwargs = {}
+ formfield = formfield_callback(f, **kwargs)
if formfield:
field_list.append((f.name, formfield))
return SortedDict(field_list)
@@ -154,12 +158,13 @@
self.model = getattr(options, 'model', None)
self.fields = getattr(options, 'fields', None)
self.exclude = getattr(options, 'exclude', None)
+ self.widgets = getattr(options, 'widgets', None)
class ModelFormMetaclass(type):
def __new__(cls, name, bases, attrs):
formfield_callback = attrs.pop('formfield_callback',
- lambda f: f.formfield())
+ lambda f, **kwargs: f.formfield(**kwargs))
try:
parents = [b for b in bases if issubclass(b, ModelForm)]
except NameError:
@@ -177,7 +182,7 @@
if opts.model:
# If a model is defined, extract form fields from it.
fields = fields_for_model(opts.model, opts.fields,
- opts.exclude, formfield_callback)
+ opts.exclude, opts.widgets, formfield_callback)
# Override default model fields with any custom declared ones
# (plus, include all the other declared fields).
fields.update(declared_fields)
=== modified file 'docs/topics/forms/modelforms.txt'
--- docs/topics/forms/modelforms.txt 2008-09-27 17:49:41 +0000
+++ docs/topics/forms/modelforms.txt 2008-09-27 17:53:20 +0000
@@ -305,16 +305,33 @@
.. _section on saving forms: `The save() method`_
-Overriding the default field types
-----------------------------------
+Overriding the default field types or widgets
+---------------------------------------------
The default field types, as described in the `Field types`_ table above, are
sensible defaults. If you have a ``DateField`` in your model, chances are you'd
want that to be represented as a ``DateField`` in your form. But
-``ModelForm`` gives you the flexibility of changing the form field type
-for a given model field. You do this by declaratively specifying fields like
-you would in a regular ``Form``. Declared fields will override the default
-ones generated by using the ``model`` attribute.
+``ModelForm`` gives you the flexibility of changing the form field type and
+widget for a given model field.
+
+To specify a custom widget for a field use the ``widgets`` attribute og the
+inner ``Meta`` class. For example if you want the default textarea for the TextField
+to have custom ``cols`` and ``rows`` attributes you can override its widget:
+
+>>> class ArticleForm(ModelForm)
+... class Meta:
+... model = ArticleForm
+... fields = ['title', 'text']
+... widgets = {
+... 'text': Textarea(attrs={'cols': 80, 'rows': 20})
+... }
+
+``Widgets`` dictionary accepts both widget instances (i.e. ``Textarea(...)``) as well
+as classes (i.e. ``Textarea``).
+
+If you want to further customize the field including its type, label etc., you do this
+by declaratively specifying fields like you would in a regular ``Form``. Declared
+fields will override the default ones generated by using the ``model`` attribute.
For example, if you wanted to use ``MyDateFormField`` for the ``pub_date``
field, you could do the following::
@@ -325,11 +342,11 @@
... class Meta:
... model = Article
-If you want to override a field's default widget, then specify the ``widget``
+If you want to override a field's default label, then specify the ``label``
parameter when declaring the form field::
>>> class ArticleForm(ModelForm):
- ... pub_date = DateField(widget=MyDateWidget())
+ ... pub_date = DateField(label='Publication date')
...
... class Meta:
... model = Article
=== modified file 'tests/modeltests/model_forms/models.py'
--- tests/modeltests/model_forms/models.py 2008-09-27 17:49:41 +0000
+++ tests/modeltests/model_forms/models.py 2008-09-28 23:07:22 +0000
@@ -220,6 +220,27 @@
>>> CategoryForm.base_fields.keys()
['name']
+Using 'widgets'
+
+>>> class CategoryForm(ModelForm):
+...
+... class Meta:
+... model = Category
+... fields = ['name', 'url', 'slug']
+... widgets = {
+... 'name': forms.Textarea,
+... 'url': forms.TextInput(attrs={'class': 'url'})
+... }
+
+>>> str(CategoryForm()['name'])
+''
+
+>>> str(CategoryForm()['url'])
+''
+
+>>> str(CategoryForm()['slug'])
+''
+
Don't allow more than one 'model' definition in the inheritance hierarchy.
Technically, it would generate a valid form, but the fact that the resulting
save method won't deal with multiple objects is likely to trip up people not