Login

DropDownMultiple widget

Author:
marinho
Posted:
May 9, 2008
Language:
Python
Version:
.96
Score:
2 (after 2 ratings)

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

  1. Template tag - list punctuation for a list of items by shapiromatron 3 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 11 months ago
  5. Help text hyperlinks by sa2812 11 months, 3 weeks ago

Comments

marinho (on May 13, 2008):

Fixed problem when selecting in an already filled select object.

#

Please login first before commenting.