I was recently refactoring some old code to use a ModelForm and was
stuck at an issue that we don't have a simple way to say "this form has
these fields from a model but with other widgets".
For example I have an Article model that I want to edit in a form:
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['author', 'text']
This is nice! But now I want to use a bit larger textarea for 'text' and
want specify it with attrs={'cols': 80, 'rows': 20}. Currently I have
two options:
1. Redeclare entire field:
class ArticleForm(ModelForm):
text = CharField(
u'Text',
is_required=True,
widget=Textarea(...))
class Meta:
model = Article
fields = ['author']
The problem is that along with a widget I have to repeat other
attributes of a field: type, label, required-ness, help_text etc...
Which is bad because it's, ahem, "non DRY" :-). It's also looks a bit
strange because now fields are declared in two different ways.
2. Fix widget in __init__:
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['author', 'text']
def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs)
self.fields['text'].widget = Textarea(...)
Here the problem is that it has enough boilerplate code to be, shall we
say, not beautiful. And also it defeats nice declarative nature of a
ModelForm.
In other words the problem of ModelForm is that we have very usefule
separation between fields and widgets but we cannot declare them separately.
## Proposal
To fix this I was thinking along the lines of:
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['author', 'text']
widgets = {
'text': Textarea(...),
}
I know it can be done now with formfieldcallback but it doesn't look
nearly as readable because you have to write an imperative logic
comparing field names.
Sound sane?
regards
Steve
--
Steve Holden +1 571 484 6266 +1 800 494 3119
Holden Web LLC http://www.holdenweb.com/
For styling. Choosing widgets has nothing to do with styling. My cols
and rows for textarea is just an example that, incidently, can be
emulated with CSS. But often you want to use a different widget
altogether, say, a set of radio buttons instead of default select multiple.
P.S. And if you allow me to be pedantic, cols and rows attributes are
not presentational. They even required by HTML 4.01. So CSS here is not
an adequate replacement.
Yes, together with dynamic choices will perform great (on init,
developers might assign some options to widgets...).
And before it's landed into the trunk (i hope it will ;) ) you can
make your own subclass of ModelForm which does exactly what you
proposed, and then subclass it everywhere ;)
--
Best regards, Yuri V. Baburov, ICQ# 99934676, Skype: yuri.baburov,
MSN: bu...@live.com
Yuri, it's a bit redundant note :-). Sure everyone can subclass anything
or patch Django installation. I'm merely asking *if* it's sane enough to
be in Django itself. If yes I'm happy to make a patch.
1) You missed making a subclass as third option in your initial post
(and preferred one), that's why i suggested it.
2) "Sure everyone can subclass anything or patch Django installation"
is not much realistic statement: for some things, it's much easier
than for other ;)
3) Why I think your idea is good, and why I vote +1 for it:
Adding more and more declarative options to ModelForm and for NFA's
ModelAdmin is good, cause it's making simple forms easier to write.
90% of application forms are typical, let's make them declarative if
it's possible.
100% of developers want to make their simple forms even more simple
(some forms will always be custom).
No, I mean kinda dynamic_FIELD_choices methods, as it was suggested
for ModelAdmin.
> On Jul 6, 11:20 pm, Ivan Sagalaev <man...@softwaremaniacs.org> wrote:
>> Yuri Baburov wrote:
>> > And before it's landed into the trunk (i hope it will ;) ) you can
>> > make your own subclass of ModelForm which does exactly what you
>> > proposed, and then subclass it everywhere ;)
>>
>> Yuri, it's a bit redundant note :-). Sure everyone can subclass anything
>> or patch Django installation. I'm merely asking *if* it's sane enough to
>> be in Django itself. If yes I'm happy to make a patch.
> >
>
--
+1. I think this would wrap up one of the last reasons to use
formfield_callback, but I think it should be on the post-1.0 list.
Joseph
Basically, because I was struggling with widgets many times but didn't
have any practical needs for changing a label, for example. I don't say
it's useless or something but I just can't defend it from my experience.
> By the way, IIRC the following should already somewhat do what you
> want in most cases, although it's obviously not very nice:
>
> class ArticleForm(ModelForm):
> author =
> Article._meta.get_field('author').formfield(**custom_options)
> class Meta:
> model = Article
I do something like this right now. I even have a shortcut function
"model_field" for this which makes it shorter. However, see:
class ArticleForm(ModelForm):
author = model_field(Article, 'author', attrs)
class Meta:
model = Article
every such field definition forces me to repeat field's name twice and
also repeat a model that is already set in Meta.
Hello everyone!
I've just got to implementing this:
http://code.djangoproject.com/ticket/9223
The patch is rather simple, backwards-compatible, contains tests and
docs. I suppose docs require some proof-reading, as usual.
You've forgot to call `super` :-). I know that it's only an example but
it adds another line and also shows that such things can easily be
forgotten in real code.
> Do we really need another way of doing this? Or am I overlooking
> something that this new method introduces?
I've addressed this exact thing my first email on subject, so quoting
myself:
> Here the problem is that it has enough boilerplate code to be, shall we
> say, not beautiful. And also it defeats nice declarative nature of a
> ModelForm.
So, yes, it's not the end of the world but it's the same convenience as
`fields` or `exclude` that all could be simulated in __init__.
Full customization already can be done by specifying fields directly in
a form class. In my experience widgets are just very common case.
May be... I just don't like how it looks. Apart from repeating model
name for each field and field's own name twice it is not as readable as
a couple of params in Meta that clearly show in what the form is
different from default state.