Shouldn't custom fields in ModelForms pick up model Field options by default?

41 views
Skip to first unread message

Kevin Henry

unread,
Aug 12, 2009, 11:05:37 PM8/12/09
to Django developers
Take a simple Model and ModelForm like this:

class Author(models.Model):
name = models.CharField(max_length=80, blank=True, default="Joe",
help_text="A name")

class AuthorForm(forms.ModelForm):

class Meta:
model = Author

The resulting form will reflect the desired help text, default, and
blank options.

But if you decide to customize the widget, for example:

class AuthorForm(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput(attrs={'size':80}))

class Meta:
model = Author

the form field no longer reflects these model field options (that is,
there is no help text, no default value, and you can't save it blank).

This seems like undesirable behavior. At the very least it's
surprising, and should probably be documented here:
http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-default-field-types.

I'm fairly new to Django, so unfortunately I'm not sure of the right
way to do this. One workaround is to set the fields manually, like:

name = forms.CharField(widget=forms.TextInput(attrs={'size':80}),
required=False, initial="Joe", help_text="A name")

but that's an obvious violation of DRY. Another workaround, which
takes advantage of the fact that the options are getting properly set
in the call to the model field's formfield() method, is this:

name = Author._meta.get_field("name").formfield
(form_class=forms.CharField, widget=forms.TextInput(attrs={'size':
80}))

but that's not ideal either, for obvious reasons.

Any thoughts?

Malcolm Tredinnick

unread,
Aug 12, 2009, 11:15:52 PM8/12/09
to django-d...@googlegroups.com
On Wed, 2009-08-12 at 20:05 -0700, Kevin Henry wrote:
[...]

> But if you decide to customize the widget, for example:
>
> class AuthorForm(forms.ModelForm):
> name = forms.CharField(widget=forms.TextInput(attrs={'size':80}))
>
> class Meta:
> model = Author
>
> the form field no longer reflects these model field options (that is,
> there is no help text, no default value, and you can't save it blank).

Correct. You told Django that you wanted to specify the field yourself
and it believed you. Django cannot know which attributes you intended to
leave out and which you wanted inherited, so it does the only possible
thing and leaves things entirely in your control.

>
> This seems like undesirable behavior. At the very least it's
> surprising,

Well, surprise is in the eye of the participant. As noted above, it
would be surprising to a lot of us if it did pick up the attributes
because it removes control from the user. The current behaviour isn't
illogical.

Definitely. Please open a ticket (if one doesn't already exist in the
documentation component for this) and feel free to attach a patch with
some suggested wording.

>
> I'm fairly new to Django, so unfortunately I'm not sure of the right
> way to do this.

If all you want to do is change the widget, you can do that in the
form's __init__ method by updating self.fields["name"].widget, for
example.

Regards,
Malcolm


Kevin Henry

unread,
Aug 13, 2009, 3:59:51 PM8/13/09
to Django developers
> Well, surprise is in the eye of the participant. As noted above, it
> would be surprising to a lot of us if it did pick up the attributes
> because it removes control from the user. The current behaviour isn't
> illogical.

Oh, I wasn't suggesting that the user shouldn't be able to override
those values, I was only talking about what the default behavior
should be if the user doesn't specify anything. If the user
instantiates a form field, and doesn't specify what 'required' should
be (and the field itself doesn't set this value), it just seems far
more natural to pick up the value the user already specified in the
model, rather than arbitrarily choosing 'True'.

Part of the reason I think this represents a common use case is that
these attributes seem fairly orthogonal to the purposes of validating/
rendering that fields and widgets are used for. That is, I wouldn't
imagine that it's common that your choice of which field or widget to
use to represent a model field will affect whether or not that field
is required, say. Of course, my experience is limited.

I don't know enough yet to suggest how this would be implemented, I
just wanted to throw the idea out there. But unless there's a
groundswell of support for my position, I guess I'll just file a
documentation ticket.

Cheers,
Kevin

Brian Rosner

unread,
Aug 13, 2009, 4:12:53 PM8/13/09
to django-d...@googlegroups.com

On Aug 13, 2009, at 1:59 PM, Kevin Henry wrote:

>
>> Well, surprise is in the eye of the participant. As noted above, it
>> would be surprising to a lot of us if it did pick up the attributes
>> because it removes control from the user. The current behaviour isn't
>> illogical.
>
> Oh, I wasn't suggesting that the user shouldn't be able to override
> those values, I was only talking about what the default behavior
> should be if the user doesn't specify anything. If the user
> instantiates a form field, and doesn't specify what 'required' should
> be (and the field itself doesn't set this value), it just seems far
> more natural to pick up the value the user already specified in the
> model, rather than arbitrarily choosing 'True'.

It isn't choosing arbitrary defaults. When you declare a form field
declaratively in your ModelForm we have to assume you want that field
and everything that comes with it. So, behind the scenes the declared
form field simply overrides what is the field for that particular
field. Therefore the value it uses in-place of the model form field is
the default value for that attribute of that form field you've just
declared as being the replacement.

>
> Part of the reason I think this represents a common use case is that
> these attributes seem fairly orthogonal to the purposes of validating/
> rendering that fields and widgets are used for. That is, I wouldn't
> imagine that it's common that your choice of which field or widget to
> use to represent a model field will affect whether or not that field
> is required, say. Of course, my experience is limited.

I won't argue that you are wrong here, but to accomplish what you have
asked for is going to involve more trickery than it is really worth
(plus being backwards incompatible at this point). There has been
mention of providing a simpler way to overriding widgets for a field
(as that is the common case) without affecting the field. That
particular proposal will go further than what you've brought up.

>
> I don't know enough yet to suggest how this would be implemented, I
> just wanted to throw the idea out there. But unless there's a
> groundswell of support for my position, I guess I'll just file a
> documentation ticket.

No doubt the documentation needs to be revised slightly for this. It
is mentioned, but only as a single sentence that almost makes no
sense ;-)

Please file a ticket for the documentation fix it would be greatly
appreciated. :-)

Brian Rosner
http://oebfare.com

dc

unread,
Aug 13, 2009, 4:15:46 PM8/13/09
to Django developers
If you want inherit default attributes from model just use

name = Author._meta.get_field('name').formfield()

Ivan Sagalaev

unread,
Aug 13, 2009, 5:02:57 PM8/13/09
to django-d...@googlegroups.com
Malcolm Tredinnick wrote:
> If all you want to do is change the widget, you can do that in the
> form's __init__ method by updating self.fields["name"].widget, for
> example.

There's also a ticket waiting for check-in implementing this common
usecase: http://code.djangoproject.com/ticket/9223

P.S. Sorry for the shameless plug :-)

Kevin Henry

unread,
Aug 15, 2009, 4:58:22 AM8/15/09
to Django developers
In terms of backward compatibility, perhaps there could be a new
keyword argument to Field, something like with_model_defaults, that
the user would use to indicate a desire to get the attributes from the
Model. How would this work? Maybe something like this (this is just a
sketch): Field.__init__() works the same way, except that it also
stores the value of the keyword arguments (with_model_defaults, as
well as the others, since the user should be able to override
individual settings). Then ModelForm's metaclass will call a method on
the field, passing in the field name. The field can then extract the
default values from the Model and set itself up appropriately.

Too much trickery? Before looking into how Django works I would have
definitely said yes, but now my standards have changed. :) (That's not
a criticism, I'm very happy with the trickery Django implies to make
life easier for the user.)


> There's also a ticket waiting for check-in implementing this common
> usecase:http://code.djangoproject.com/ticket/9223

Thanks, the accompanying discussion is very interesting and on point.
But as someone there points out, why stop at widgets? The discussion
strengthens my intuition that widgets, fields, and the attributes I'm
discussing here are fairly orthogonal concepts, and the current all-or-
nothing declarative syntax couples them too tightly. Both your
solution and the (much less thought-out) one I just proposed feel too
small to me, but I'm not sure of a better solution.

Cheers,
Kevin

Kevin Henry

unread,
Aug 15, 2009, 4:59:18 AM8/15/09
to Django developers
> Please file a ticket for the documentation fix it would be greatly  
> appreciated. :-)

Will do.

Ivan Sagalaev

unread,
Aug 15, 2009, 3:52:31 PM8/15/09
to django-d...@googlegroups.com
Kevin Henry wrote:
>> There's also a ticket waiting for check-in implementing this common
>> usecase:http://code.djangoproject.com/ticket/9223
>
> Thanks, the accompanying discussion is very interesting and on point.
> But as someone there points out, why stop at widgets?

Because customizing widgets is a common request, unlike other attributes.

I believe that the consistency you're talking about is not very useful
here. Speaking from my experience overwriting anything other than a
widget is needed rarely and is easily accomplished with a custom 2-line
helper function.

Kevin Henry

unread,
Aug 15, 2009, 11:53:52 PM8/15/09
to Django developers
> > Thanks, the accompanying discussion is very interesting and on point.
> > But as someone there points out, why stop at widgets?
>
> Because customizing widgets is a common request, unlike other attributes.

But customizing fields is quite common, no? I agree that it's rare
that you will want to override required, help_text, etc.—in fact,
that's exactly my point. The current syntax forces you to do so when
customizing the form just to get back to the behavior already
specified in the model. Your solution solves this problem for the
common case of customizing the widget, but the issue is just as
applicable for the common case of customizing the field.

But at this point, I'll come up with a more concrete proposal before
carrying on.
Reply all
Reply to author
Forward
0 new messages