views:

282

answers:

2

I am creating a form that uses MultipleChoiceField. The values for this field are derived from another model. This method works fine, however, I am noticing (on the production server) that when I add a new item to the model in question (NoticeType), the form does not dynamically update. I have to restart the server for the new item to show up on my MultipleChoiceField.

Any changes to the NoticeType model (editing items or creating new ones) do not propagate to the form. After I restart the production server, the updates appear.

Any ideas why this might be ? The relevant portion of the form is below. Thanks.

from django import forms 
from django.contrib.auth.models import User
from notification.models import NoticeType

class EditUserProfileForm(forms.Form):   
    CHOICES = []

    for notice in NoticeType.objects.all():
        CHOICES.append( (notice.label,notice.display) )

    notifications   = forms.MultipleChoiceField(
                        label="Email Notifications",
                        required=False,
                        choices=( CHOICES ),
                        widget=forms.CheckboxSelectMultiple,)
+3  A: 

My hunch is that the class definition is only being processed once on load rather than for each instantiation. Try adding the CHOICES computation to the init method like so:

def __init__(self, *args, **kwargs):
    super(self.__class__, self).__init__(*args, **kwargs)
    CHOICES = []
    for notice in NoticeType.objects.all():
        CHOICES.append( (notice.label, notice.display) )
    self.fields['notifications'].choices = CHOICES
Hey! Great - that fixed it immediately. After I posted I had a similiar thought, actually, but wasn't thinking about the `__init__()` method ... I thought I could create a new function outside the class that returned the list ... but I like this even better. Thank you!
thornomad
+5  A: 

Although mherren is right that you can fix this problem by defining your choices in the __init__ method, there is an easier way: use the ModelMultipleChoiceField which is specifically designed to take a queryset, and updates dynamically.

class EditUserProfileForm(forms.Form):
    notifications = forms. ModelMultipleChoiceField(
                    label="Email Notifications",
                    required=False,
                    queryset = NoticeType.objects.all(),
                    widget=forms.CheckboxSelectMultiple)
Daniel Roseman
That is even sexier! And I thought it couldn't get any better - thanks for that. Will be making that adjustment saving some precious space in my codebase. Thanks.
thornomad
Using this technique would I still be able to specify which model field is shown as the "text" on the form?
thornomad
By default it uses the `__unicode__` representation. If you need something different, you'll need to subclass ModelMultipleChoiceField and override `label_from_instance`, as described here: http://docs.djangoproject.com/en/dev/ref/forms/fields/#modelchoicefield
Daniel Roseman
Thanks - I think I may go that route because, I assume, it seems to be the way "the django" wants it. I am new to stackoverflow - should I post my final "working" code as an "answer" after I am done?
thornomad