Pandemonium Illusion

Better way to use Django’s SelectMultiple in Google App Engine for a ListProperty

August 20, 2008 · 8 Comments

So my last post was a quick hack attempt at this, but I have come up with a much cleaner method of getting a GAE ListProperty field to work with Django Forms (newforms). You simply have to create a new form field called ListPropertyChoice:

from django.newforms.fields import MultipleChoiceField
from appengine_django.models import BaseModel

class ListPropertyChoice(MultipleChoiceField):

    def clean(self, value):
        """ extending the clean method to work with GAE keys """
        new_value = super(ListPropertyChoice, self).clean(value)
        key_list = []
        for k in new_value:
            key_list.append(BaseModel.get(k).key())
        return key_list

You can then use this in your forms:

...
from fields import ListPropertyChoice

class Form(djangoforms.ModelForm):
    my_model = ListPropertyChoice(
                        widget=forms.CheckboxSelectMultiple(),
                        choices=[(m.key(), m.name) for m in db.Query(MyModel)]
                    )
    class Meta:
        model = ParentModel

Obviously you can use both the SelectMultiple widget and the CheckboxSelectMultiple widget and this same process could be easily duplicated for ChoiceField:

class GAEChoiceField(ChoiceField):
    def clean(self, value):
        """ extending the clean method to work with GAE keys """
        value = super(GAEChoiceField, self).clean(value)
        return BaseModel.get(value).key()

Categories: App Engine · django · webdev
Tagged: , , , ,

8 responses so far ↓

  • SelectMultiple for a Google App Engine ListProperty using Django Forms « Pandemonium Illusion // August 20, 2008 at 2:03 am | Reply

    [...] 15, 2008 · 1 Comment EDIT: I recently posted a better way to do [...]

  • hugo // January 28, 2009 at 10:56 pm | Reply

    hey .. great post. it just does not validate here for me ;( would be glad if you could show how to actually dump this to datastore in the end, perhaps? ;) thx!

  • jamstooks // January 28, 2009 at 11:56 pm | Reply

    Hi hugo,

    I just used this again the other day with the latest version of Django. Are you using the form’s save method?

    The clean() methods return the values and then they are saved to BigTable using form.save().

    When you say they aren’t “validating,” do you mean the form isn’t submitting? If so, you might make sure you’re populating your choices list correctly with ((‘key’,'name’),).

    Hope that helps.

  • hugo // January 29, 2009 at 12:15 pm | Reply

    Hello jamstooks,

    thanks for your fast reply.

    the form looks all good here, it has the key’s as values and sends them over as a UnicodeMultiDict .. ([(u'my_tags', u'ahBpbnRlcm5ldHJhZGlvYm94cg8LEgRUYWdzIgVhbW91cgw'), (u'my_tags', u'ahBpbnRlcm5ldHJhZGlvYm94cg8LEgRUYWdzIgViYWlsZQw'), (u'my_tags', u'ahBpbnRlcm5ldHJhZGlvYm94cg8LEgRUYWdzIgVzYWxzYQw')])

    my problem is, the clean_method of the ListPropertyChoice does not seem to like my data at all, when I try to pass it on e.g.:
    data = TagForm(data=self.request.POST, instance=station)
    data.errors tells me my_tagsEnter a list of values.

    no luck with a list either..
    data_raw = self.request.get(‘my_tags’, allow_multiple=True)

    I’m using the exact code from your sample above, on the most recent vanilla GAE sdk.

    Man, I wish I had posted this earlier .. ;)
    Would be so glad to get this done, finally ..

    Cheers, Hugo

  • hugo // January 29, 2009 at 4:12 pm | Reply

    seems like there is only the first choice / element of the multidict/POST is passed to the validation/clean() method, and not the full choice that was made. I noticed that when the “for k in new_value” started decomposing the single key.. I’m clueless

  • hugo // January 30, 2009 at 11:45 am | Reply

    another question that raises, is the choices=[] populated on first run only, and not updated when there are new values? hope you bear with me ;)

  • jamstooks // January 30, 2009 at 2:32 pm | Reply

    Good point about the population of choices only one time. Use an init function if you want to repopulate every time it’s displayed.
    http://www.djangosnippets.org/snippets/26/

  • Andrew // May 29, 2009 at 8:37 pm | Reply

    To get more than one value use self.request.POST.mixed() instead of just self.request.POST when passing the data to the form.

Leave a Comment