Ticket #9223: 9223.diff

File 9223.diff, 5.8 KB (added by Ivan Sagalaev, 16 years ago)

Patch with test and docs

  • django/forms/models.py

     
    123123            data[f.name] = f.value_from_object(instance)
    124124    return data
    125125
    126 def fields_for_model(model, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()):
     126def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
    127127    """
    128128    Returns a ``SortedDict`` containing form fields for the given model.
    129129
     
    137137    # TODO: if fields is provided, it would be nice to return fields in that order
    138138    field_list = []
    139139    opts = model._meta
     140    kwargs = {}
    140141    for f in opts.fields + opts.many_to_many:
    141142        if not f.editable:
    142143            continue
     
    144145            continue
    145146        if exclude and f.name in exclude:
    146147            continue
    147         formfield = formfield_callback(f)
     148        if widgets and f.name in widgets:
     149            kwargs['widget'] = widgets[f.name]
     150        formfield = formfield_callback(f, **kwargs)
    148151        if formfield:
    149152            field_list.append((f.name, formfield))
    150153    return SortedDict(field_list)
     
    154157        self.model = getattr(options, 'model', None)
    155158        self.fields = getattr(options, 'fields', None)
    156159        self.exclude = getattr(options, 'exclude', None)
     160        self.widgets = getattr(options, 'widgets', None)
    157161
    158162
    159163class ModelFormMetaclass(type):
    160164    def __new__(cls, name, bases, attrs):
    161165        formfield_callback = attrs.pop('formfield_callback',
    162                 lambda f: f.formfield())
     166                lambda f, **kwargs: f.formfield(**kwargs))
    163167        try:
    164168            parents = [b for b in bases if issubclass(b, ModelForm)]
    165169        except NameError:
     
    177181        if opts.model:
    178182            # If a model is defined, extract form fields from it.
    179183            fields = fields_for_model(opts.model, opts.fields,
    180                                       opts.exclude, formfield_callback)
     184                                      opts.exclude, opts.widgets, formfield_callback)
    181185            # Override default model fields with any custom declared ones
    182186            # (plus, include all the other declared fields).
    183187            fields.update(declared_fields)
  • tests/modeltests/model_forms/models.py

     
    220220>>> CategoryForm.base_fields.keys()
    221221['name']
    222222
     223Using 'widgets'
     224
     225>>> class CategoryForm(ModelForm):
     226...
     227...     class Meta:
     228...         model = Category
     229...         fields = ['name', 'url']
     230...         widgets = {
     231...             'name': forms.Textarea,
     232...             'url': forms.TextInput(attrs={'class': 'url'})
     233...         }
     234
     235>>> str(CategoryForm()['name'])
     236'<textarea id="id_name" rows="10" cols="40" name="name"></textarea>'
     237
     238>>> str(CategoryForm()['url'])
     239'<input id="id_url" type="text" class="url" name="url" maxlength="40" />'
     240
    223241Don't allow more than one 'model' definition in the inheritance hierarchy.
    224242Technically, it would generate a valid form, but the fact that the resulting
    225243save method won't deal with multiple objects is likely to trip up people not
  • docs/topics/forms/modelforms.txt

     
    305305
    306306.. _section on saving forms: `The save() method`_
    307307
    308 Overriding the default field types
    309 ----------------------------------
     308Overriding the default field types or widgets
     309---------------------------------------------
    310310
    311311The default field types, as described in the `Field types`_ table above, are
    312312sensible defaults. If you have a ``DateField`` in your model, chances are you'd
    313313want that to be represented as a ``DateField`` in your form. But
    314 ``ModelForm`` gives you the flexibility of changing the form field type
    315 for a given model field. You do this by declaratively specifying fields like
    316 you would in a regular ``Form``. Declared fields will override the default
    317 ones generated by using the ``model`` attribute.
     314``ModelForm`` gives you the flexibility of changing the form field type and
     315widget for a given model field.
    318316
     317To specify a custom widget for a field use the ``widgets`` attribute og the
     318inner ``Meta`` class. For example if you want the default textarea for the TextField
     319to have custom ``cols`` and ``rows`` attributes you can override its widget:
     320
     321>>> class ArticleForm(ModelForm)
     322...     class Meta:
     323...         model = ArticleForm
     324...         fields = ['title', 'text']
     325...         widgets = {
     326...             'text': Textarea(attrs={'cols': 80, 'rows': 20})
     327...         }
     328
     329``Widgets`` dictionary accepts both widget instances (i.e. ``Textarea(...)``) as well
     330as classes (i.e. ``Textarea``).
     331
     332If you want to further customize the field including its type, label etc., you do this
     333by declaratively specifying fields like you would in a regular ``Form``. Declared
     334fields will override the default ones generated by using the ``model`` attribute.
     335
    319336For example, if you wanted to use ``MyDateFormField`` for the ``pub_date``
    320337field, you could do the following::
    321338
     
    325342    ...     class Meta:
    326343    ...         model = Article
    327344
    328 If you want to override a field's default widget, then specify the ``widget``
     345If you want to override a field's default label, then specify the ``label``
    329346parameter when declaring the form field::
    330347
    331348   >>> class ArticleForm(ModelForm):
    332    ...     pub_date = DateField(widget=MyDateWidget())
     349   ...     pub_date = DateField(label='Publication date')
    333350   ...
    334351   ...     class Meta:
    335352   ...         model = Article
Back to Top