Code

Ticket #1164: manipulator_contexts.diff

File manipulator_contexts.diff, 14.2 KB (added by jkocherhans <jkocherhans@…>, 9 years ago)
Line 
1Index: django/contrib/admin/views/stages/add.py
2===================================================================
3--- django/contrib/admin/views/stages/add.py    (revision 1817)
4+++ django/contrib/admin/views/stages/add.py    (working copy)
5@@ -4,6 +4,7 @@
6 from django.contrib.admin.views.stages.modify import render_change_form
7 from django.core import formfields, template
8 from django.core.extensions import DjangoContext as Context
9+from django.core.extensions import ManipulatorContext
10 from django.db import models
11 from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
12 from django.utils.text import capfirst, get_text_list
13@@ -22,7 +23,8 @@
14 
15     if not request.user.has_perm(app_label + '.' + opts.get_add_permission()):
16         raise PermissionDenied
17-    manipulator = model.AddManipulator()
18+    context = ManipulatorContext(model, request)
19+    manipulator = model.AddManipulator(context=context)
20     if request.POST:
21         new_data = request.POST.copy()
22         if opts.has_field_type(models.FileField):
23Index: django/contrib/admin/views/stages/change.py
24===================================================================
25--- django/contrib/admin/views/stages/change.py (revision 1817)
26+++ django/contrib/admin/views/stages/change.py (working copy)
27@@ -1,6 +1,7 @@
28 from django.contrib.admin.views.main import get_model_and_app
29 from django.core import formfields, template
30 from django.core.extensions import DjangoContext as Context
31+from django.core.extensions import ManipulatorContext
32 from django.contrib.admin.views.stages.modify import render_change_form
33 from django.db import models
34 from django.utils.text import capfirst, get_text_list
35@@ -36,9 +37,10 @@
36         raise PermissionDenied
37     if request.POST and request.POST.has_key("_saveasnew"):
38         return add_stage(request, path, form_url='../../add/')
39+    context = ManipulatorContext(model, request)
40     
41     try:
42-        manipulator = model.ChangeManipulator(object_id)
43+        manipulator = model.ChangeManipulator(object_id, context=context)
44     except ObjectDoesNotExist:
45         raise Http404
46 
47Index: django/db/models/manipulators.py
48===================================================================
49--- django/db/models/manipulators.py    (revision 1817)
50+++ django/db/models/manipulators.py    (working copy)
51@@ -62,6 +62,9 @@
52 
53     name = property(_get_name)
54 
55+# TODO: I don't like initializing the manipulator with the context, but it's
56+# easier than passing around the context to a bunch of different methods in
57+# the manipulator       
58 class AutomaticManipulator(Manipulator, Naming):
59     def _prepare(cls, model):
60         cls.model = model
61@@ -82,7 +85,7 @@
62         setattr(other_cls, name, ManipulatorDescriptor(name, cls))
63     contribute_to_class = classmethod(contribute_to_class)
64 
65-    def __init__(self, original_object=None, follow=None, name_parts=() ):
66+    def __init__(self, original_object=None, follow=None, name_parts=(), context=None):
67         Naming.__init__(self, name_parts)
68         if name_parts == ():
69             self.follow = self.model._meta.get_follow(follow)
70@@ -90,9 +93,10 @@
71             self.follow = follow
72         self.fields_, self.children = [], {}
73         self.original_object = original_object
74+        self.context = context
75         for f in self.opts.get_data_holders(self.follow):
76             fol = self.follow[f.name]
77-            fields,manipulators = f.get_fields_and_manipulators(self.opts, self, follow=fol)
78+            fields,manipulators = f.get_fields_and_manipulators(self.opts, self, follow=fol, context=self.context)
79 
80             if fields != None:
81                 self.fields_.extend(fields)
82@@ -145,7 +149,7 @@
83                 # Fields with auto_now_add should keep their original value in the change stage.
84                 auto_now_add = self.change and getattr(f, 'auto_now_add', False)
85                 if self.follow.get(f.name, None) and not auto_now_add:
86-                    param = f.get_manipulator_new_data(expanded_data)
87+                    param = f.get_manipulator_new_data(expanded_data, context=self.context)
88                 else:
89                     param = self.get_original_value(f)
90             params[f.attname] = param
91@@ -280,8 +284,8 @@
92 class ModelAddManipulator(AutomaticManipulator):
93     change = False
94     add = True
95-    def __init__(self, follow=None, name_parts=()):
96-        super(ModelAddManipulator, self).__init__(follow=follow, name_parts=name_parts)
97+    def __init__(self, follow=None, name_parts=(), context=None):
98+        super(ModelAddManipulator, self).__init__(follow=follow, name_parts=name_parts, context=context)
99 
100     def get_original_value(self, field):
101         return field.get_default()
102@@ -293,7 +297,7 @@
103     change = True
104     add = False
105 
106-    def __init__(self, obj_key=None, follow=None, name_parts=()):
107+    def __init__(self, obj_key=None, follow=None, name_parts=(), context=None):
108         assert obj_key is not None, "ChangeManipulator.__init__() must be passed obj_key parameter."
109         opts = self.model._meta
110         if isinstance(obj_key, self.model):
111@@ -321,7 +325,7 @@
112                 else:
113                     raise
114 
115-        super(ModelChangeManipulator, self).__init__(original_object=original_object, follow=follow, name_parts=name_parts)
116+        super(ModelChangeManipulator, self).__init__(original_object=original_object, follow=follow, name_parts=name_parts, context=context)
117         #self.original_object = original_object
118 
119         #if self.opts.get_ordered_objects():
120@@ -336,10 +340,11 @@
121         return "<Automatic ChangeManipulator '%s' for %s:%r >" % (self.name_prefix, self.model.__name__, self.obj_key)
122 
123 class ManipulatorCollection(list, Naming):
124-    def __init__(self, model, follow, name_parts=()):
125+    def __init__(self, model, follow, name_parts=(), context=None):
126         Naming.__init__(self, name_parts)
127         self.model = model
128         self.follow = follow
129+        self.context = context
130         self._load()
131 
132     def _get_list(self):
133@@ -349,7 +354,7 @@
134         man_class = self.model.ChangeManipulator
135 
136         for i,obj in enumerate(self._get_list()):
137-            self.append(man_class(obj,self.follow, self.name_parts + (str(i),)  ))
138+            self.append(man_class(obj, self.follow, self.name_parts + (str(i),), context=self.context))
139 
140     def _save_child(self, manip, parent_key):
141         manip.save_from_update()
142@@ -438,7 +443,7 @@
143             self.append(None)
144 
145         prefix = '%s%s.' % (self.name_prefix, index )
146-        child_manip = man_class(self.follow, self.name_parts + ( str(index), )  )
147+        child_manip = man_class(self.follow, self.name_parts + (str(index),), context=self.context)
148 
149         self[index] = child_manip
150         return child_manip
151Index: django/db/models/fields/__init__.py
152===================================================================
153--- django/db/models/fields/__init__.py (revision 1817)
154+++ django/db/models/fields/__init__.py (working copy)
155@@ -218,7 +218,7 @@
156             field_objs = self.get_manipulator_field_objs()
157         return (field_objs,params)
158 
159-    def get_fields_and_manipulators(self, opts, manipulator, follow ):
160+    def get_fields_and_manipulators(self, opts, manipulator, follow, context=None):
161         change = manipulator.change
162         rel = manipulator.name_prefix != ''
163         name_prefix = manipulator.name_prefix
164@@ -278,7 +278,7 @@
165     def get_validator_unique_lookup_type(self):
166         return '%s__exact' % f.name
167 
168-    def get_manipulator_new_data(self, new_data, rel=False):
169+    def get_manipulator_new_data(self, new_data, rel=False, context=None):
170         """
171         Given the full new_data dictionary (from the manipulator), returns this
172         field's data.
173@@ -329,6 +329,9 @@
174     def bind(self, fieldmapping, original, bound_field_class=BoundField):
175         return bound_field_class(self, fieldmapping, original)
176 
177+    def get_context_processors(self):
178+        return []
179+
180 class AutoField(Field):
181     empty_strings_allowed = False
182     def __init__(self, *args, **kwargs):
183@@ -343,13 +346,13 @@
184     def get_manipulator_field_objs(self):
185         return [formfields.HiddenField]
186 
187-    def get_manipulator_new_data(self, new_data, rel=False):
188+    def get_manipulator_new_data(self, new_data, rel=False, context=None):
189         # Never going to be called
190         # Not in main change pages
191         # ignored in related context
192         if not rel:
193             return None
194-        return Field.get_manipulator_new_data(self, new_data, rel)
195+        return Field.get_manipulator_new_data(self, new_data, rel, context)
196 
197     def contribute_to_class(self, cls, name):
198         if cls._meta.has_auto_field:
199@@ -440,7 +443,7 @@
200     def get_manipulator_field_names(self, name_prefix):
201         return [name_prefix + self.name + '_date', name_prefix + self.name + '_time']
202 
203-    def get_manipulator_new_data(self, new_data, rel=False):
204+    def get_manipulator_new_data(self, new_data, rel=False, context=None):
205         date_field, time_field = self.get_manipulator_field_names('')
206         #if rel:
207         #    d = new_data.get(date_field, [None])[0]
208Index: django/db/models/related.py
209===================================================================
210--- django/db/models/related.py (revision 1817)
211+++ django/db/models/related.py (working copy)
212@@ -1,12 +1,12 @@
213 from django.db.models.manipulators import ManipulatorCollection
214 
215 class RelatedManipulatorCollection(ManipulatorCollection):
216-    def __init__(self,related, parent_name_parts , instance, follow):
217+    def __init__(self, related, parent_name_parts , instance, follow, context=None):
218         name_parts = parent_name_parts + (related.var_name, )
219         self.instance = instance
220         self.related = related
221         super(RelatedManipulatorCollection, self).__init__(
222-            related.model,follow,name_parts)
223+            related.model, follow, name_parts, context)
224         
225     def _save_child(self, manip, parent_key):
226         setattr(manip.original_object, self.related.field.attname, parent_key)
227@@ -96,14 +96,14 @@
228     def __repr__(self):
229         return "<RelatedObject: %s related to %s>" % (self.name, self.field.name)
230 
231-    def get_fields_and_manipulators(self, opts, manipulator, follow ):
232-        return ([], self.get_manipulators(manipulator, follow)  )
233+    def get_fields_and_manipulators(self, opts, manipulator, follow, context=None):
234+        return ([], self.get_manipulators(manipulator, follow, context)  )
235 
236-    def get_manipulators(self,parent_manipulator, follow):
237+    def get_manipulators(self, parent_manipulator, follow, context=None):
238         name_parts = parent_manipulator.name_parts
239         obj = parent_manipulator.original_object
240         
241-        return RelatedManipulatorCollection(self, name_parts, obj, follow)
242+        return RelatedManipulatorCollection(self, name_parts, obj, follow, context)
243 
244     def bind(self, field_mapping, original, bound_related_object_class=BoundRelatedObject):
245         return bound_related_object_class(self, field_mapping, original)
246Index: django/core/extensions.py
247===================================================================
248--- django/core/extensions.py   (revision 1817)
249+++ django/core/extensions.py   (working copy)
250@@ -62,6 +62,34 @@
251         for processor in get_standard_processors() + processors:
252             self.update(processor(request))
253 
254+# TODO: should this really be a subclass of template.Context? It should
255+# (mostly) behave the same, but really has nothing to do with the template
256+# system. Maybe template.Context ought to be moved to just django.core.Context
257+class ManipulatorContext(Context):
258+    """
259+    This subclass of template.Context automatically populates itself using
260+    the processors defined in each field's get_context_processors method.
261+    Additional processors can be specified as a list of callables
262+    using the "processors" keyword argument.
263+    """
264+    def __init__(self, model, request, dict=None, processors=None):
265+        Context.__init__(self, dict)
266+
267+        standard_processors = []
268+        # Get all the processors from the fields in this model.
269+        for f in model._meta.fields:
270+            field_context_processors = f.get_context_processors()
271+            standard_processors.extend(field_context_processors)
272+        standard_processors = tuple(standard_processors)
273+        if processors is None:
274+            processors = ()
275+        else:
276+            processors = tuple(processors)
277+        for processor in standard_processors + processors:
278+            self.update(processor(request))
279+
280+
281+
282 # PermWrapper and PermLookupDict proxy the permissions system into objects that
283 # the template system can understand.
284 
285Index: django/views/generic/create_update.py
286===================================================================
287--- django/views/generic/create_update.py       (revision 1817)
288+++ django/views/generic/create_update.py       (working copy)
289@@ -3,7 +3,7 @@
290 from django.core.template import loader
291 from django.core import formfields, meta
292 from django.views.auth.login import redirect_to_login
293-from django.core.extensions import DjangoContext
294+from django.core.extensions import DjangoContext, ManipulatorContext
295 from django.core.paginator import ObjectPaginator, InvalidPage
296 from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
297 from django.core.exceptions import Http404, ObjectDoesNotExist, ImproperlyConfigured
298@@ -23,7 +23,8 @@
299         return redirect_to_login(request.path)
300 
301     mod = models.get_module(app_label, module_name)
302-    manipulator = mod.AddManipulator(follow=follow)
303+    context = ManipulatorContext(mod, request)
304+    manipulator = model.AddManipulator(follow=follow, context=context)
305     if request.POST:
306         # If data was POSTed, we're trying to create a new object
307         new_data = request.POST.copy()
308@@ -88,6 +89,7 @@
309         return redirect_to_login(request.path)
310 
311     mod = models.get_module(app_label, module_name)
312+    context = ManipulatorContext(mod, request)
313 
314     # Look up the object to be edited
315     lookup_kwargs = {}
316@@ -103,7 +105,7 @@
317     except ObjectDoesNotExist:
318         raise Http404("%s.%s does not exist for %s" % (app_label, module_name, lookup_kwargs))
319 
320-    manipulator = mod.ChangeManipulator(object.id, follow=follow)
321+    manipulator = mod.ChangeManipulator(object.id, follow=follow, context=context)
322 
323     if request.POST:
324         new_data = request.POST.copy()