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) |
---|