Here is the model (simplified to bare bones):
class away(models.Model):
contact = models.ForeignKey(Contact, verbose_name="Name of person
away", limit_choices_to= {'is_staff':True}, db_column='contact')
As you can see Contact is another model being referenced here which
has a field named "is_staff" that I want to use to filter out some
contacts so that they do not display as options in my form to add or
edit away instances. Unfortunately, the filter seems to only affect
the way the field is displayed in the admin forms, not on regular
forms.
This is how the start of my view to edit away instances looks like:
def away_edit(request, away_id):
aw = get_object_or_404(away, id=away_id)
aw_form = forms.form_for_instance(aw)
When displaying that form the 'contact' field displays as a dropdown
list, but it includes the choices I wanted filtered out. So, after a
lot of searching, I found this post which seems to be addressing the
same issue:
However, I can't make it work. This is how I have translated the
advice to my view:
def away_edit(request, away_id):
aw = get_object_or_404(away, id=away_id)
aw_form = forms.form_for_instance(aw)
aw_form.base_fields['contact']=forms.ChoiceField(choices=[(obj.id,
obj.name) for obj in Contact.objects.filter(is_staff=True)])
When I do that, the form displays correctly and it actually does
filter out the choices as I want. But, when I submit the form I get
an error telling me that "away_away.contact may not be NULL".
Can someone please explain to me why it gives me that error?
'Contact' object has no attribute 'name'
But, when I use this code,
def away_edit(request, away_id):
aw = get_object_or_404(away, id=away_id)
aw_form = forms.form_for_instance(aw)
aw_form.base_fields['contact']=forms.ChoiceField(choices=[(obj.id,
obj) for obj in Contact.objects.filter(is_staff=True)])
The form displays correctly and it actually does filter out the
choices as I want. But, when I submit the form I get an error telling
me that "away_away.contact may not be NULL". I am a lost. Thanks
for any help you can give.
class away_form(forms.Form):
contact =
forms.ModelChoiceField(queryset=Contact.objects.filter(is_staff=True),
label="Person away")
However, even that is not intuitive since one would assume that since
the form is reading the field definition from the model it would know
to use any filters specified there. So, I think this is a design flaw
in the current implementation, in my little insignificant opinion. I
think all forms should, by default, honor any filter used in the model
definition. I guess a way of overriding that could be provided, if
there are *exceptional* cases that require something different.
Doesn't this make sense?
However, even that is not intuitive since one would assume that since
the form is reading the field definition from the model it would know
to use any filters specified there. So, I think this is a design flaw
in the current implementation, in my little insignificant opinion. I
think all forms should, by default, honor any filter used in the model
definition. I guess a way of overriding that could be provided, if
there are *exceptional* cases that require something different.
Doesn't this make sense?
http://www.djangoproject.com/documentation/forms/
The thing is that in the newforms documentation no way of
accomplishing what I am after is given.
On Nov 2, 10:54 am, "Karen Tracey" <kmtra...@gmail.com> wrote:
> On 11/2/07, rm <rmcorresp...@gmail.com> wrote:[snip]
OK, so my expectations were unreasonable. (Too bad because it would
seem to be a very user friendly and elegant way of limiting choices in
forms.) So, what do you suggest as the reasonable method to limit
choices on a form_from_instance or form_from_model? Maybe I
misunderstood the part of the documentation that discourages one from
using the information on this page and encourages one to use the
newforms documentation:
http://www.djangoproject.com/documentation/forms/
The thing is that in the newforms documentation no way of
accomplishing what I am after is given.
Well, I still think that instead of decoupling the admin option from
the model, they should leave it as is and implement support for it on
all forms. It is beautiful and very Pythonic.
> As for how to do it in general, sorry I can't help there (though I got the
> impression you had found a way to do it?). My own app has no need of forms,
> so it is an area I know very little about.
Well, I thought I had found a way to do it, but I can't get it to
work, as I described already.
> I don't think you misunderstood the documentation either. Building stuff
> with oldforms is discouraged, since they are going away. But newfoms is
> still work-in-progress, so doc is not complete and some things may not be
> entirely worked out. Such is the way with volunteer projects.
Interesting dilemma. I just find it hard to believe that nobody else
has found a way to work around this issue.
def away_edit(request, away_id):
aw = get_object_or_404(away, id=away_id)
aw_form = forms.form_for_instance(aw)
filtered_choices = Contact.objects.filter(is_staff=True)
aw_form.base_fields['contact'].widget =
forms.widgets.Select(choices=[(obj.id, obj.__str__()) for obj in
filtered_choices])
Tada!!!
Any one wants to add it to the documentation or some FAQ wicky? :)
[1] http://www.djangoproject.com/documentation/newforms/#overriding-the-default-field-types
[2] http://code.djangoproject.com/ticket/4787
On Nov 1, 3:15 pm, rm <rmcorresp...@gmail.com> wrote:
> I know this is a painful subject. I have spent a couple of days
> trying to figure this out, and I am almost there. (I think. :)
>
> Here is the model (simplified to bare bones):
>
> class away(models.Model):
> contact = models.ForeignKey(Contact, verbose_name="Name of person
> away", limit_choices_to= {'is_staff':True}, db_column='contact')
>
> As you can see Contact is another model being referenced here which
> has a field named "is_staff" that I want to use to filter out some
> contacts so that they do not display as options in my form to add or
> edit away instances. Unfortunately, the filter seems to only affect
> the way the field is displayed in the admin forms, not on regular
> forms.
>
> This is how the start of my view to edit away instances looks like:
>
> def away_edit(request, away_id):
> aw = get_object_or_404(away, id=away_id)
> aw_form = forms.form_for_instance(aw)
>
> When displaying that form the 'contact' field displays as a dropdown
> list, but it includes the choices I wanted filtered out. So, after a
> lot of searching, I found this post which seems to be addressing the
> same issue:
>
> http://groups.google.com/group/django-users/browse_thread/thread/cbbf...
Usually ,assigning to base_fields is overdoing things and diving a bit
too deep.
If you can, I'd suggest keeping things simple and just assigning to
fields on the *instance* of the form. So, something like this:
aw_form = forms.form_for_instance(aw)
form_instance = aw()
form_instance.fields['contact'].choices = ...
The reason for doing it this way is that the 'contact' Field instance
has a property for "choices", so when you assign to choices, it updates
both the field's copy and the widget's version in sync. It's also just a
bit neater -- you only have to worry about "fields" and not
"base_fields" plus "fields" (you usually can't avoid "fields" if you're
using newforms).
Regards,
Malcolm
--
A clear conscience is usually the sign of a bad memory.
http://www.pointy-stick.com/blog/
Thanks for the advice. It took me a little bit of fiddling to figure
out that the proper syntax to make your suggestion work but I think I
got it.
form.fields['contact'].choices =
forms.widgets.Select.choices=[(obj.id, obj.__str__()) for obj in
filtered_choices]
I am not sure why you think it is simpler to assign fields to the
instance than to the base_fields since then you have to do it twice
per view, once for the case of the Post request and again for the case
of a blank form.
While I have your attention, I wonder if you can give me your opinion
on this variation:
form.fields['contact'].choices = forms.widgets.Select.choices=[(None,
"- - - - - - - - - - - - - - - -")]+[(obj.id, obj.__str__()) for obj
in filtered_choices]
I did that to replicate the feel of the widget that starts with a
blank choice rather than the first name on the choices list. It seems
to work. It is caught by the validator with a nice message saying:
"Please select a valid choice. That choice is not one of the
available choices." So, it looks right, but it feels like a hack. :)
On Nov 2, 9:25 pm, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:
Are we to infer, by extrapolating, that since it appears that the
coupling of the model definition and the form definition is
undesirable passing the help_text argunment to a form will eventually
not be done at the model? Instead, are we going to have to use a
formfield_callback to pass the help_text to a form_for_model, for
example?
-rm
On Nov 2, 5:11 pm, Brian Rosner <bros...@gmail.com> wrote:
> What you really need is to use the formfield_callback argument to
> form_for_instance. This allows you to override the default fields
> that are returned for a given field in the model [1]. There is an
> open bug, [2], that will allow for an easier way of overriding the
> queryset that is ultimately rendered as the options. Until then you
> will just need to subclass ModelChoiceField and re-implement the
> choices property to use a custom queryset that does the filtering you
> are describing.
>
> [1]http://www.djangoproject.com/documentation/newforms/#overriding-the-d...
Are we to infer, by extrapolating, that since it appears that the
coupling of the model definition and the form definition is
undesirable passing the help_text argunment to a form will eventually
not be done at the model? Instead, are we going to have to use a
formfield_callback to pass the help_text to a form_for_model, for
example?
-rm
On Nov 2, 5:11 pm, Brian Rosner <bros...@gmail.com> wrote:
> What you really need is to use the formfield_callback argument to
> form_for_instance. This allows you to override the default fields
> that are returned for a given field in the model [1]. There is an
> open bug, [2], that will allow for an easier way of overriding the
> queryset that is ultimately rendered as the options. Until then you
> will just need to subclass ModelChoiceField and re-implement the
> choices property to use a custom queryset that does the filtering you
> are describing.
>
> [1]http://www.djangoproject.com/documentation/newforms/#overriding-the-d...