Ticket #4467: categorizedmodelchoicefield.py

File categorizedmodelchoicefield.py, 4.8 KB (added by ulda <ulf.dambacher@…>, 17 years ago)
Line 
1# (c) + (w) by ulf.dambacher _ at _ web.de
2# License: select one from GPL Version 2 or the BSD license django uses
3#
4from django.newforms.widgets import Select
5from django.newforms.fields import ChoiceField,Field
6from django.newforms.models import ModelChoiceField
7from django.newforms.util import ValidationError
8from django.utils.translation import gettext
9
10from gertus.lib.JsonResponse import *
11
12
13class 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
96class 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
142def 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)
Back to Top