ModelMultipleChoiceField with checkboxes: How to generate the HTML "checked" option?

2,042 views
Skip to first unread message

Gloria

unread,
Nov 28, 2009, 6:05:21 PM11/28/09
to Django users
Hi all,
I've spent way too much time getting trying to get this widget to work
the way I am envisioning.
In the forms, I want to initialize it, but in the view I need to
determine which boxes are checked.
Has anyone done this without writing their own widget? It would be
great to know how.
Thank you in advance,
Gloria

Nick Arnett

unread,
Nov 29, 2009, 12:08:44 PM11/29/09
to django...@googlegroups.com

Rather than trying to do that on the client side (which is what I think you're saying), have you considered just passing the required values to the template as context variables?

Nick

Gloria

unread,
Nov 29, 2009, 12:52:26 PM11/29/09
to Django users
Thanks for the response. I am trying to do this on the server side.
Here is more detail.
I am initializing it to all unchecked checkboxes in my forms.py.
Then, in my view, I am trying to have HTML generate a "checked" value
for certain checkboxes, based on some user data I received in that
view.
How do I generate "checked" HTML option using the builtin
ModelMultipleChoiceField for certain checkboxes? Is there a builtin
option that I should set manually to cause the "checked" option to be
generated? Or do I have to iterate over these fields, match them with
data I have received, and generate the "checked" option myself, in the
template?

Thanks!

~G~

Nick Arnett

unread,
Nov 29, 2009, 3:17:36 PM11/29/09
to django...@googlegroups.com

You shouldn't have to do that if the data is available in your view.  It should be as easy as passing a dict as "initial" to your form instance you create in the view:

form = MyForm(initial = {"foo"=True, "bar"=True}

with the field names (instead of foo and bar) of the check boxes you want checked.  Your form then should have them checked when it is rendered.

Nick

levin11

unread,
Nov 29, 2009, 2:59:02 PM11/29/09
to Django users
I have ModelMultipleChoiceField working for me OK, but I am not sure I
understand your question. Could you be a bit more specific?

This is a snippet from my code which may or may not help:

class PictureForm(ModelForm):
tags = ModelMultipleChoiceField(queryset=Tag.objects.all(),
widget=CheckboxSelectMultiple, required=False)
class Meta:
model = Picture
fields = ('title', .... , 'tags')

# the view:
def edit_picture(request, pic_id):
pic = get_object_or_404(Picture, pk=pic_id)

if request.method == "POST":
pic_form = PictureForm(request.POST, instance=pic)
if pic_form.is_valid():
pic_form.save()
else:
pic_form = PictureForm(instance=pic)

return render_to_response("cat/edit_picture.html", dict(
pic_form = pic_form
))

levin11

unread,
Nov 29, 2009, 4:44:25 PM11/29/09
to Django users
Hi,

I tried to post this two hours ago, but it did not show up. So sorry
if this is the second copy.

I use "checkboxed" ModelMultipleChoiceField w/o any problems. Here is
a snippet:

class PictureForm(ModelForm):
tags = ModelMultipleChoiceField(queryset=Tag.objects.all(),
widget=CheckboxSelectMultiple, required=False)
class Meta:
model = Picture
fields = ('title', ..., 'tags')

def edit_picture(request, pic_id):
pic = get_object_or_404(Picture, pk=pic_id)

if request.method == "POST":
pic_form = PictureForm(request.POST, instance=pic)
if pic_form.is_valid() and photo_forms.is_valid():
pic_form.save()
else:
pic_form = PictureForm(instance=pic)

return render_to_response("cat/edit_picture.html", dict(
pic_form = pic_form
))

Hope this helps.

Gloria

unread,
Nov 29, 2009, 11:30:42 PM11/29/09
to Django users
Here's the line from my model:
class UserProfile(models.Model):
some other fields...
privacy_options = models.ManyToManyField(PrivacyOption,
blank=True, null=True, db_table = 'usr_privacy_selection')

Here's the bit from my form:

class ModifyProfileForm(forms.Form):
some other fields...
privacy = forms.ModelMultipleChoiceField(
queryset=PrivacyOption.objects.all(),
required=False,
show_hidden_initial=True,
widget=forms.CheckboxSelectMultiple,
)

Here's whats happening in my view.

When I initialize it like this:

data = {some other fields...
'privacy' : user_profile.privacy_options
}

form=ModifyProfileForm(data)

Then I show it in the template:
{{ form.privacy.label_tag }}
{{ form.privacy }}
{{ form.privacy.errors }}

I get this error:
Caught an exception while rendering: 'ManyRelatedManager' object is
not iterable

So I change the template like so:
{% for privacy in form.privacy.all %}
{{privacy}}
{% endfor %}

and I get this in my browser:

Privacy

* Enter a list of values.


as if it is not displaying any checkboxes because none have a value
set in them yet.

I want to display all checkboxes, and then check the ones which are
set.

I commented out this change in the view, no longer initializing the
form:

#'privacy' : user_profile.privacy_options,

and I still see nothing in my browser, unless I change the template to
this:

{{ form.privacy }}

Then, at least I see all checkboxes:

Privacy
o Show My Profile Page
o Show Expertise
o Show Affiliations
o Show Organization
o Show Contact Info
o Allow Messages

Now, let me uncomment the init again, and try to initialize this form
to the db values:
'ManyRelatedManager' object is not iterable error again.

Trying to set the initial value for this particular field also does
not seem to help:

initial_dict = {}
for x in user_profile.privacy_options.all():
initial_dict[x.name]=True

form=ModifyProfileForm(data)
form.fields['privacy'].initial = initial_dict

The selected options never show up.

I know the selections are being passed to a user_profile instance and
stored in the database. So maybe this is a template rendering issue?

Thanks again,
Gloria



Nick Arnett

unread,
Nov 29, 2009, 11:51:24 PM11/29/09
to django...@googlegroups.com
On Sun, Nov 29, 2009 at 8:30 PM, Gloria <stra...@comcast.net> wrote:
Here's the line from my model:
class UserProfile(models.Model):
   some other fields...
   privacy_options = models.ManyToManyField(PrivacyOption,
blank=True, null=True, db_table = 'usr_privacy_selection')

Here's the bit from my form:

class ModifyProfileForm(forms.Form):
   some other fields...
   privacy = forms.ModelMultipleChoiceField(
       queryset=PrivacyOption.objects.all(),
       required=False,
       show_hidden_initial=True,
       widget=forms.CheckboxSelectMultiple,
       )

Hmmm... what are you trying to do by passing the queryset?  Doesn't that send your form everybody's data, instead of just the active user?  If I recall correctly, passing a queryset will initialize a form, so perhaps all you need to do there is make it a "get" that returns only the current user's data?



When I initialize it like this:

   data = {some other fields...
       'privacy' : user_profile.privacy_options
       }

   form=ModifyProfileForm(data)

That doesn't look right.  I think should be:

 form=ModifyProfileForm(initial=data)

But I'm also not sure if your data dict is correct.  It should have an item for each field that you want to initialize. 

Trying to set the initial value for this particular field also does
not seem to help:

               initial_dict = {}
               for x in user_profile.privacy_options.all():
                       initial_dict[x.name]=True

               form=ModifyProfileForm(data)
               form.fields['privacy'].initial = initial_dict


Again, I don't quite understand why your queryset is using "all" - seems like you would just want one row ("get").  I'm not sure what the form object would do with a queryset that has multiple rows.  Your dict should be passed in the second to last line:

form=ModifyProfileForm(initial=initial_dict)

Something like your last line might work, but it is a lot more work than just passing the form the initialization dict.

Others feel free to jump in here and set me straight as needed.  I'm still fairly new to Django, so I'm no expert... but I've been struggling to learn the same stuff lately.

Nick

Gloria

unread,
Nov 30, 2009, 10:11:42 AM11/30/09
to Django users


>
> Hmmm... what are you trying to do by passing the queryset?  Doesn't that
> send your form everybody's data, instead of just the active user?

No, it doesn't. It returns all available options that users can
optionally select. Users selections of these fields are stored
elsewhere.

> If I
> recall correctly, passing a queryset will initialize a form, so perhaps all
> you need to do there is make it a "get" that returns only the current user's
> data?

I am doing this already. The problem is, getting all checkboxes, and
using the user-specific data to check the "checked" boxes isn't
working.

~G~

Gloria

unread,
Dec 1, 2009, 10:56:58 AM12/1/09
to Django users

After much digging, I discovered that I cannot iterate over a
forms.ModelMultipleChoiceField.
This explains the template iteration issue.
It seems like I need a FormSet to be able to set these values, and
iterate over them.
This is overly complicated, just for a set of checkboxes, but it looks
like it will work.
~G~
Reply all
Reply to author
Forward
0 new messages