Observation: depends on jQuery to works!
This widget works like other multiple select widgets, but it shows a drop down field for each choice user does, and aways let a blank choice at the end where the user can choose a new, etc.
Example using it:
class MyForm(forms.ModelForm):
categories = forms.Field(widget=DropDownMultiple)
def __init__(self, *args, **kwargs):
self.base_fields['categories'].widget.choices = Category.objects.values_list('id', 'name')
super(MyForm, self).__init__(*args, **kwargs)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # -*- coding: utf-8 -*-
from django.newforms import widgets
from django.utils.safestring import mark_safe
from django.utils.datastructures import MultiValueDict
from django.newforms.util import flatatt
TPL_OPTION = """<option value="%(value)s" %(selected)s>%(desc)s</option>"""
TPL_SELECT = """
<select class="dropdown_select" %(attrs)s>
%(opts)s
</select>
"""
TPL_SCRIPT = """
<script>
$('span#%(id)s>select.dropdown_select').change(function(){
var pattern = 'span#%(id)s>select.dropdown_select';
var last_item = $(pattern+':last');
if (last_item.val()) {
last_item.clone(true).appendTo($('span#%(id)s'));
$('span#%(id)s').append(' ');
};
var values = [];
for (var i=$(pattern).length-1; i>=0; i--) {
if (values.indexOf($($(pattern).get(i)).val()) >= 0) {
$($(pattern).get(i)).remove();
} else {
values.push($($(pattern).get(i)).val());
}
};
});
</script>
"""
TPL_FULL = """
<span class="dropdown_multiple" id="%(id)s">
%(values)s
%(script)s
</span>
"""
class DropDownMultiple(widgets.Widget):
choices = None
def __init__(self, attrs=None, choices=()):
self.choices = choices
super(DropDownMultiple, self).__init__(attrs)
def render(self, name, value, attrs=None, choices=()):
if value is None: value = []
final_attrs = self.build_attrs(attrs, name=name)
# Pop id
id = final_attrs['id']
del final_attrs['id']
# Insert blank value
choices = [('','---')] + list(self.choices)
# Build values
items = []
for val in value:
opts = "\n".join([TPL_OPTION %{'value': k, 'desc': v, 'selected': val == k and 'selected="selected"' or ''} for k, v in choices])
items.append(TPL_SELECT %{'attrs': flatatt(final_attrs), 'opts': opts})
# Build blank value
opts = "\n".join([TPL_OPTION %{'value': k, 'desc': v, 'selected': ''} for k, v in choices])
items.append(TPL_SELECT %{'attrs': flatatt(final_attrs), 'opts': opts})
script = TPL_SCRIPT %{'id': id}
output = TPL_FULL %{'id': id, 'values': '\n'.join(items), 'script': script}
return mark_safe(output)
def value_from_datadict(self, data, files, name):
if isinstance(data, MultiValueDict):
return [i for i in data.getlist(name) if i]
return data.get(name, None)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 11 months, 3 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 4 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
- Help text hyperlinks by sa2812 1 year, 8 months ago
Comments
Fixed problem when selecting in an already filled select object.
#
Please login first before commenting.