Extending forms.SelectMultiple Without Losing Values
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 rea开发者_开发知识库dability</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.
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.
精彩评论