1 | # (c) + (w) by ulf.dambacher _ at _ web.de
|
---|
2 | # License: select one from GPL Version 2 or the BSD license django uses
|
---|
3 | #
|
---|
4 | from django.newforms.widgets import Select
|
---|
5 | from django.newforms.fields import ChoiceField,Field
|
---|
6 | from django.newforms.models import ModelChoiceField
|
---|
7 | from django.newforms.util import ValidationError
|
---|
8 | from django.utils.translation import gettext
|
---|
9 |
|
---|
10 | from gertus.lib.JsonResponse import *
|
---|
11 |
|
---|
12 |
|
---|
13 | class CategorizedSelect(Select):
|
---|
14 |
|
---|
15 | category_field= '%s_category'
|
---|
16 | value_field = '%s'
|
---|
17 |
|
---|
18 | def __init__(self, attrs=None, categories=(),choices=(),callback_link='',settings_for_value=None ):
|
---|
19 | self.categories=list(categories)
|
---|
20 | self.choices=list(choices)
|
---|
21 | self.attrs = attrs or {}
|
---|
22 | self.callback_link=callback_link
|
---|
23 | self.settings_for_value=settings_for_value
|
---|
24 |
|
---|
25 | def render(self, name, value, attrs=None):
|
---|
26 |
|
---|
27 |
|
---|
28 | category_value=None
|
---|
29 | value_value=None
|
---|
30 | if value:
|
---|
31 | value_value=value
|
---|
32 | if self.settings_for_value:
|
---|
33 | (self.categories,self.choices,category_value) = self.settings_for_value(value)
|
---|
34 |
|
---|
35 | output = [
|
---|
36 | """
|
---|
37 | <script type="text/javascript">
|
---|
38 | """,
|
---|
39 | 'function %s_update(select) {' % (self.value_field % name),
|
---|
40 | """
|
---|
41 | //loesche Auswahlliste
|
---|
42 | """,
|
---|
43 | ' var elem= select.form.elements["%s"]'% (self.value_field % name) ,
|
---|
44 | """
|
---|
45 | for(i = 0; i<= elem.length; i+=1 )
|
---|
46 | elem.options[i]=null;
|
---|
47 |
|
---|
48 | //und lade die Liste neu
|
---|
49 | req = new HTTP.Request({
|
---|
50 | method:'get',
|
---|
51 |
|
---|
52 | """,
|
---|
53 | " uri: '%s', \n" % self.callback_link,
|
---|
54 | """
|
---|
55 | parameters: 'category='+select.options[select.options.selectedIndex].value,
|
---|
56 | onSuccess: function (trans) {
|
---|
57 | var data;
|
---|
58 | try {
|
---|
59 | var data = eval('('+trans.responseText+')');
|
---|
60 | } catch(e) {
|
---|
61 | alert('eval: Ungueltiges JSON: ' + e);
|
---|
62 | return;
|
---|
63 | };
|
---|
64 |
|
---|
65 | // alert(trans.responseText);
|
---|
66 |
|
---|
67 | for ( i=0;i < data.length; i+=1) {
|
---|
68 | elem.add(new Option( data[i][1], data[i][0], false , false ) , null );
|
---|
69 | };
|
---|
70 | }
|
---|
71 | });
|
---|
72 | }
|
---|
73 | </script>
|
---|
74 | """
|
---|
75 | ]
|
---|
76 |
|
---|
77 | select_html = Select(choices=self.categories).render(
|
---|
78 | self.category_field % name,
|
---|
79 | category_value,
|
---|
80 | attrs={ 'onchange': "%s_update(this)" % (self.value_field %name) },
|
---|
81 | )
|
---|
82 | output.append(select_html)
|
---|
83 |
|
---|
84 | select_html = Select(choices=self.choices).render(
|
---|
85 | self.value_field % name,
|
---|
86 | value_value,
|
---|
87 | )
|
---|
88 | output.append(select_html)
|
---|
89 |
|
---|
90 | return u'\n'.join(output)
|
---|
91 |
|
---|
92 | def value_from_datadict(self, data, name):
|
---|
93 | return data.get(self.value_field % name)
|
---|
94 |
|
---|
95 |
|
---|
96 | class CategorizedModelChoiceField(ModelChoiceField):
|
---|
97 | """A ChoiceField for selecting for selecting from a queryset
|
---|
98 | but with narrowing the selection by using a category"""
|
---|
99 |
|
---|
100 | def __init__(self, queryset, category, callback_link, empty_label=u"---------",
|
---|
101 | required=True, widget=CategorizedSelect, label=None, initial=None, help_text=None):
|
---|
102 |
|
---|
103 | # Call Field instead of ChoiceField __init__() because we don't need
|
---|
104 | # ChoiceField.__init__().
|
---|
105 | Field.__init__(self, required, widget, label, initial, help_text)
|
---|
106 | self.queryset = queryset
|
---|
107 | self.category_name=category
|
---|
108 | self.empty_label = empty_label
|
---|
109 | self.widget.categories=self.categories
|
---|
110 | self.widget.choices=self.get_choices_for_category(self.categories[0][0])
|
---|
111 | self.widget.callback_link=self.callback_link=callback_link
|
---|
112 | self.widget.settings_for_value=lambda x: self.widgetsettings_for_value(x)
|
---|
113 |
|
---|
114 | def _get_categories(self):
|
---|
115 |
|
---|
116 | cat=set()
|
---|
117 | for i in self.queryset.values( self.category_name):
|
---|
118 | cat.add( i[self.category_name])
|
---|
119 |
|
---|
120 | choices=dict(self.queryset.model._meta.get_field(self.category_name).choices)
|
---|
121 | return [ ( i , choices.get(i,i) ) for i in cat]
|
---|
122 |
|
---|
123 | def _set_categories(self,value):
|
---|
124 | self._categories=self.widget.categories=list(value)
|
---|
125 |
|
---|
126 | def get_choices_for_category(self, category):
|
---|
127 | my_list=[]
|
---|
128 | for obj in self.queryset.filter( **{ self.category_name: category} ):
|
---|
129 | my_list.append( ( obj.id, str(obj) ) )
|
---|
130 | return my_list
|
---|
131 |
|
---|
132 | categories= property(_get_categories, _set_categories)
|
---|
133 |
|
---|
134 | #callback-function for widget
|
---|
135 | def widgetsettings_for_value(self,value):
|
---|
136 | obj = self.queryset.model._default_manager.get(pk=value)
|
---|
137 | category=getattr(obj, self.category_name)
|
---|
138 | return (self.categories,self.get_choices_for_category(category),category)
|
---|
139 |
|
---|
140 |
|
---|
141 | # this defines a view for the callback-url
|
---|
142 | def get_choices_for_category(request, queryset, category_name):
|
---|
143 | my_category=request.GET.get('category',None)
|
---|
144 |
|
---|
145 | my_list=[]
|
---|
146 | if my_category:
|
---|
147 | for obj in queryset.filter( **{ category_name: my_category} ):
|
---|
148 | my_list.append( ( obj.id, str(obj) ) )
|
---|
149 | else:
|
---|
150 | my_list.append( ('-', 'please select a category first' ) )
|
---|
151 |
|
---|
152 | return JsonResponse(my_list)
|
---|