Code

Ticket #10557: trac-10557.2.diff

File trac-10557.2.diff, 6.6 KB (added by steph, 3 years ago)

Better patch with argument inspection

Line 
1diff --git a/django/contrib/formtools/tests/__init__.py b/django/contrib/formtools/tests/__init__.py
2index 9c7d46f..b194845 100644
3--- a/django/contrib/formtools/tests/__init__.py
4+++ b/django/contrib/formtools/tests/__init__.py
5@@ -360,3 +360,34 @@ class WizardTests(TestCase):
6                 "wizard_step": "1"}
7         wizard(DummyRequest(POST=data))
8 
9+    def test_prev_fields_as_hidden(self):
10+        """
11+        Previous fields should be available as hidden fields.
12+        """
13+        data = {"0-field": "test",
14+                "1-field": "test2",
15+                "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
16+                "wizard_step": "1"}
17+
18+        previous_fields = '<input type="hidden" name="0-field" value="test" id="id_0-field" /><input type="hidden" name="hash_0" value="7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c" id="id_hash_0" /><input type="hidden" name="1-field" value="test2" id="id_1-field" /><input type="hidden" name="hash_1" value="d5b434e3934cc92fee4bd2964c4ebc06f81d362d" id="id_hash_1" />'
19+
20+        response = self.client.post('/wizard/', data)
21+        self.assertEquals(2, response.context['step0'])
22+        self.assertEquals(previous_fields, response.context['previous_fields'])
23+
24+    def test_prev_fields_as_list(self):
25+        """
26+        Previous fields should be available as hidden fields.
27+        """
28+        data = {"0-field": "test",
29+                "1-field": "test2",
30+                "hash_0": "7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c",
31+                "wizard_step": "1"}
32+
33+        response = self.client.post('/wizard/', data)
34+        self.assertEquals(2, response.context['step0'])
35+
36+        the_fields = [(f.html_name, f.data if f.form.is_bound else f.form.initial.get(f.name, f.field.initial)) for f in response.context['previous_fields_list']]
37+
38+        self.assertEquals(the_fields, [('0-field', u'test'), ('hash_0', u'7e9cea465f6a10a6fb47fcea65cb9a76350c9a5c'), ('1-field', u'test2'), ('hash_1', 'd5b434e3934cc92fee4bd2964c4ebc06f81d362d')])
39+
40diff --git a/django/contrib/formtools/wizard.py b/django/contrib/formtools/wizard.py
41index d382e29..a1c6af2 100644
42--- a/django/contrib/formtools/wizard.py
43+++ b/django/contrib/formtools/wizard.py
44@@ -5,10 +5,12 @@ stored on the server side.
45 """
46 
47 import cPickle as pickle
48+import inspect
49 
50 from django import forms
51 from django.conf import settings
52 from django.contrib.formtools.utils import security_hash, form_hmac
53+from django.forms.forms import BoundField
54 from django.http import Http404
55 from django.shortcuts import render_to_response
56 from django.template.context import RequestContext
57@@ -145,13 +147,29 @@ class FormWizard(object):
58         prev_fields = []
59         if old_data:
60             hidden = forms.HiddenInput()
61-            # Collect all data from previous steps and render it as HTML hidden fields.
62+            # Collect all data from previous steps
63             for i in range(step):
64                 old_form = self.get_form(i, old_data)
65                 hash_name = 'hash_%s' % i
66-                prev_fields.extend([bf.as_hidden() for bf in old_form])
67-                prev_fields.append(hidden.render(hash_name, old_data.get(hash_name, self.security_hash(request, old_form))))
68-        return self.render_template(request, form, ''.join(prev_fields), step, context)
69+                prev_fields.extend([bf for bf in old_form])
70+                hash_field = forms.Field(
71+                    initial=old_data.get(
72+                        hash_name,
73+                        self.security_hash(request, old_form)))
74+                hash_bf = BoundField(forms.Form(), hash_field, hash_name)
75+                prev_fields.append(hash_bf)
76+
77+        # render the previous fields as HTML hidden fields.
78+        html_prev_fields = ''.join([f.as_hidden() for f in prev_fields])
79+
80+        method_args = inspect.getargspec(self.render_template).args
81+        if 'previous_fields_list' in method_args:
82+            return self.render_template(request, form, html_prev_fields,
83+                                        step, context,
84+                                        previous_fields_list=prev_fields)
85+        else:
86+            return self.render_template(request, form, html_prev_fields,
87+                                        step, context)
88 
89     # METHODS SUBCLASSES MIGHT OVERRIDE IF APPROPRIATE ########################
90 
91@@ -223,7 +241,8 @@ class FormWizard(object):
92         """
93         return 'forms/wizard.html'
94 
95-    def render_template(self, request, form, previous_fields, step, context=None):
96+    def render_template(self, request, form, previous_fields,
97+                        step, context=None, previous_fields_list=None):
98         """
99         Renders the template for the given step, returning an HttpResponse object.
100 
101@@ -243,6 +262,11 @@ class FormWizard(object):
102                           hidden fields. Note that you'll need to run this
103                           through the "safe" template filter, to prevent
104                           auto-escaping, because it's raw HTML.
105+            previous_fields_list -- A list containing every previous data
106+                          field, plus hashes for completed forms, all in the
107+                          form of regular fields. Note that you'll need to
108+                          call :meth:`as_hidden` on each field to prevent
109+                          them from appearing in your forms.
110         """
111         context = context or {}
112         context.update(self.extra_context)
113@@ -252,7 +276,8 @@ class FormWizard(object):
114             step=step + 1,
115             step_count=self.num_steps(),
116             form=form,
117-            previous_fields=previous_fields
118+            previous_fields=previous_fields,
119+            previous_fields_list=previous_fields_list
120         ), context_instance=RequestContext(request))
121 
122     def process_step(self, request, form, step):
123diff --git a/docs/ref/contrib/formtools/form-wizard.txt b/docs/ref/contrib/formtools/form-wizard.txt
124index 370fbdc..653e27e 100644
125--- a/docs/ref/contrib/formtools/form-wizard.txt
126+++ b/docs/ref/contrib/formtools/form-wizard.txt
127@@ -152,6 +152,10 @@ This template expects the following context:
128       plus hashes for completed forms, all in the form of hidden fields. Note
129       that you'll need to run this through the :tfilter:`safe` template filter,
130       to prevent auto-escaping, because it's raw HTML.
131+    ' ``previous_fields_list`` -- A list containing every previous data field,
132+      plus hashes for completed forms, all in the form of regular fields. Note
133+      that you'll need to call :meth:`as_hidden` on each field to prevent them
134+      from appearing in your forms.
135 
136 You can supply extra context to this template in two ways:
137