views:

85

answers:

1

I have a model form that I am writing a custom widget for in order to replace the many-to-many forms.SelectMultiple fields with jQuery FCBKcomplete widgets. While the replacement of the multiselect element works fine, it is no longer pulling the options for the multiselect.

Here is my widget:

class FCBKcompleteWidget(forms.SelectMultiple):
    def _media(self):
        return forms.Media(js=(reverse('appstatic',
                                       args=['js/jquery.fcbkcomplete.min.js']),
                               reverse('appstatic',
                                       args=['js/init-fcbkcomplete.js'])),
                           css={'all': (reverse('appstatic',
                                                args=['css/jquery.fcbkcomplete'
                                                      '.css']),)})

    media = property(_media)

Here is my form:

class BlogForm(forms.ModelForm):
    class Meta(object):
        model = models.Blog
        exclude = ('slug',)

    def __init__(self, *args, **kwargs):
        super(BlogForm, self).__init__(*args, **kwargs)
        self.fields['description'].widget = TinyMCEWidget()

        fcbkcomplete_fields = ['categories', 'admins', 'editors']

        for field in fcbkcomplete_fields:
            self.fields[field].widget = FCBKcompleteWidget()

Here are my models:

class Category(models.Model):
    """A blog category"""

    title = models.CharField(max_length=128)
    slug = models.SlugField()

    class Meta(object):
        verbose_name_plural = u'Categories'

    def __unicode__(self):
        return self.title

    @models.permalink
    def get_absolute_url(self):
        return ('category', (), {'slug': self.slug})


class Blog(models.Model):
    """A blog"""

    title = models.CharField(max_length=128)
    slug = models.SlugField(unique=True)
    description = models.TextField()
    categories = models.ManyToManyField(Category, related_name='blogs')
    shared = models.BooleanField()
    admins = models.ManyToManyField(User, related_name='blog_admins')
    editors = models.ManyToManyField(User, related_name='blog_editors')

    def __unicode__(self):
        return self.title

    @models.permalink
    def get_absolute_url(self):
        return ('blog', (), {'slug': self.slug})

Here is the resulting HTML:

<div class="field">
  <label for="name">Categories</label>
  <select multiple="multiple" name="categories" id="id_categories">
  </select>
  <div class="help-text">trimmed for readability</div>
</div>
<div class="field">
  <label for="name">Admins</label>
  <select multiple="multiple" name="admins" id="id_admins">
  </select>
  <div class="help-text">trimmed for readability</div>
</div>
<div class="field">
  <label for="name">Editors</label>
  <select multiple="multiple" name="editors" id="id_editors">
  </select>
  <div class="help-text">trimmed for readability</div>
</div>

As you can see, none of the options are making it into the multiselect element. Here is the resulting HTML when I don't replace the widget with my custom one:

<div class="field">
  <label for="name">Categories</label>
  <select multiple="multiple" name="categories" id="id_categories">
    <option value="1" selected="selected">Good Stuff</option>
  </select>
  <div class="help-text">trimmed</div>
</div>
<div class="field">
  <label for="name">Admins</label>
  <select multiple="multiple" name="admins" id="id_admins">
    <option value="2" selected="selected">username</option>
    <option value="3">some username</option>
    <option value="4">another username</option>
  </select>
  <div class="help-text">trimmed</div>
</div>
<div class="field">
  <label for="name">Editors</label>
  <select multiple="multiple" name="editors" id="id_editors">
    <option value="2" selected="selected">username</option>
    <option value="3">some username</option>
    <option value="4">another username</option>
  </select>
  <div class="help-text">trimmed</div>
</div>

Does anyone have any suggestions as to why the options are not making it through the widget replacement process? Any help would be greatly appreciated.

A: 

1 year passed, but answer may be valuable even with current django version.

Reason for such behavior seems to missing CHOICES property for fcbk fields just push choices to the Form

class EmailSubscriptionFilterForm(forms.ModelForm):

    class Meta:
        model = EmailSubscription
        exclude = ('dsts',)

    def loc_name(self, id):
        return Location.objects.get(id = id).name           

    def __init__(self, *args, **kwargs):
        super(EmailSubscriptionFilterForm, self).__init__(*args, **kwargs)
        fcbkcomplete_fields = ['orgs']
        for field in fcbkcomplete_fields:
            self.fields[field].widget = MultiOriginSelect()
        if args:
            self.fields['orgs'].choices = ([(int(o), self.loc_name(int(o))) for o in args[0].getlist('orgs')] )

to init, it will add all options which came with POST request to the select body.

Andrew