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}))
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.
> 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.
>> 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. :-)
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.
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.)
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.
> 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.
> > 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.