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

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()
Advertisements

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

  1. Pingback: SelectMultiple for a Google App Engine ListProperty using Django Forms « Pandemonium Illusion

  2. 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!

  3. 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.

  4. 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

  5. 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

  6. 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 😉

  7. 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/

  8. 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 Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s