Hello,

There was some discussion on the current limitations of the ModelForm
API in the past couple of days on IRC, I'd like to make a proposal to
address some of them.

I wrote django-floppyforms, a library that lets you render forms using
templates instead of python code. It behaves exactly like the Django
forms library, the only difference is the import path. Import
`floppyforms as forms` and when you render a form, the HTML code comes
from templates.

There is still a limitation with ModelForms: since there is no way to
globally override the model field -> form field/widget mapping since
ModelForms fields come from the model definition. I documented this
here:

http://django-floppyforms.readthedocs.org/en/latest/differences.html#modelforms

It is possible to override widgets using the Meta.widgets dict but not
in a way that would switch all the ModelForm's fields to
template-based widgets automatically. The idea is to have custom
ModelForm subclasses with specific strategy on the model field -> form
field mapping.

This is currently possible using something called `formfield_callback`
as a ModelForm class attribute: it is simply a callback that takes a
db field and returns a form field. But this callback is a) private and
b) limited: it gets lost in the inheritance chain as described in
ticket #12915:

https://code.djangoproject.com/ticket/12915

A discussion thread was started a couple of days ago for a design
decision about formfield_callback: should we consider its behaviour as
buggy or leave it as it is? In fact formfield_callback is only used by
the admin, which has custom widgets for pretty much every db field.
This customization is done using the following methods and attributes
(all in django/contrib/admin/options.py):

FORMFIELD_FOR_DBFIELD_DEFAULTS
ModelAdmin.formfield_overrides
ModelAdmin.formfield_for_dbfield(db_field, **kwargs)
ModelAdmin.formfield_for_choicefield(db_field, **kwargs)
ModelAdmin.formfield_for_foreignkey(db_field, **kwargs)
ModelAdmin.formfield_for_manytomany(db_field, **kwargs)

In most cases those methods end up calling formfield() on the DB field
object, with some arguments for customizing the field class (wrongly
called `form_class`) and its constructor arguments (widget, label,
help_text, required, etc).

The arguments to db_field.formfield() are passed via the
formfield_callback function I mentioned earlier.

My proposal is to move that field customization API from the
ModelAdmin class back to ModelForm:

* Move formfield_for_* to ModelForm and document them as public APIs
* Deprecate `formfield_callback`
* Write an AdminModelForm class that implements all the admin form
fields and widgets customization
* Modify ModelAdmin to make use of that base class
* (maybe?) deprecate ModelForm.Meta.widgets in favor of something
similar to the admin's formfield_overrides, which is more generic.

I see the following advantages to this:

* This would allow people to have "site-wide" fields/widgets
overrides, which is a feature that the admin is already proving
useful. Write a nice date picker once, register it for all your
DateFields globally.

* Maintainers of form libraries can ship a base ModelForm class that
implements custom fields/widgets while keeping API compatibility with
Django.

Backwards-compatibility shouldn't be an issue as this touches only a
couple of ModelAdmin methods. Regarding formfield_callback, despite it
being a private API I'm not sure it can be removed safely. There are
references to it on StackOverflow and on the Django bug tracker.

I'm happy to work on a patch if core devs agree to accept this. Thoughts?

Regards,
Bruno

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to