Code

Ticket #16744: 16744.diff

File 16744.diff, 8.8 KB (added by tobias, 3 years ago)

patch reflecting the requested doc and code changes in the pull request

Line 
1diff --git a/django/views/generic/base.py b/django/views/generic/base.py
2index ea14281..45e0a99 100644
3--- a/django/views/generic/base.py
4+++ b/django/views/generic/base.py
5@@ -117,7 +117,8 @@ class TemplateView(TemplateResponseMixin, View):
6     """
7     def get_context_data(self, **kwargs):
8         return {
9-            'params': kwargs
10+            'params': kwargs,
11+            'view': self
12         }
13 
14     def get(self, request, *args, **kwargs):
15diff --git a/django/views/generic/detail.py b/django/views/generic/detail.py
16index ab21573..6e84cb5 100644
17--- a/django/views/generic/detail.py
18+++ b/django/views/generic/detail.py
19@@ -87,6 +87,8 @@ class SingleObjectMixin(object):
20 
21     def get_context_data(self, **kwargs):
22         context = kwargs
23+        if 'view' not in context:
24+            context['view'] = self
25         context_object_name = self.get_context_object_name(self.object)
26         if context_object_name:
27             context[context_object_name] = self.object
28diff --git a/django/views/generic/edit.py b/django/views/generic/edit.py
29index 3cade52..6c53e27 100644
30--- a/django/views/generic/edit.py
31+++ b/django/views/generic/edit.py
32@@ -46,6 +46,8 @@ class FormMixin(object):
33         return kwargs
34 
35     def get_context_data(self, **kwargs):
36+        if 'view' not in kwargs:
37+            kwargs['view'] = self
38         return kwargs
39 
40     def get_success_url(self):
41@@ -90,7 +92,7 @@ class ModelFormMixin(FormMixin, SingleObjectMixin):
42 
43     def get_form_kwargs(self):
44         """
45-        Returns the keyword arguments for instanciating the form.
46+        Returns the keyword arguments for instantiating the form.
47         """
48         kwargs = super(ModelFormMixin, self).get_form_kwargs()
49         kwargs.update({'instance': self.object})
50@@ -114,6 +116,8 @@ class ModelFormMixin(FormMixin, SingleObjectMixin):
51 
52     def get_context_data(self, **kwargs):
53         context = kwargs
54+        if 'view' not in context:
55+            context['view'] = self
56         if self.object:
57             context['object'] = self.object
58             context_object_name = self.get_context_object_name(self.object)
59diff --git a/django/views/generic/list.py b/django/views/generic/list.py
60index 9797356..e04656a 100644
61--- a/django/views/generic/list.py
62+++ b/django/views/generic/list.py
63@@ -94,14 +94,16 @@ class MultipleObjectMixin(object):
64                 'paginator': paginator,
65                 'page_obj': page,
66                 'is_paginated': is_paginated,
67-                'object_list': queryset
68+                'object_list': queryset,
69+                'view': self
70             }
71         else:
72             context = {
73                 'paginator': None,
74                 'page_obj': None,
75                 'is_paginated': False,
76-                'object_list': queryset
77+                'object_list': queryset,
78+                'view': self
79             }
80         context.update(kwargs)
81         if context_object_name is not None:
82diff --git a/docs/ref/class-based-views.txt b/docs/ref/class-based-views.txt
83index 692417e..a851bf8 100644
84--- a/docs/ref/class-based-views.txt
85+++ b/docs/ref/class-based-views.txt
86@@ -879,6 +879,21 @@ View
87         The default implementation returns ``HttpResponseNotAllowed`` with list
88         of allowed methods in plain text.
89 
90+    **Context**
91+
92+    .. versionadded:: 1.4
93+
94+    * ``view``: The template context of all class-based generic views will
95+      include a ``view`` variable that points to the ``View`` instance.
96+
97+      .. admonition:: Use ``alters_data`` where appropriate
98+
99+          Note that having the view instance in the template context may expose
100+          potentially hazardous methods to template authors.  To prevent methods
101+          like this from being called in the template, set ``alters_data=True``
102+          on those methods.  For more information, the documention on
103+          :ref:`rendering a template context <start-alters-data-description>`.
104+
105 TemplateView
106 ~~~~~~~~~~~~
107 .. class:: TemplateView()
108diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
109index 2b7d354..6bae4ef 100644
110--- a/docs/ref/templates/api.txt
111+++ b/docs/ref/templates/api.txt
112@@ -195,6 +195,8 @@ straight lookups. Here are some things to keep in mind:
113 * A variable can only be called if it has no required arguments. Otherwise,
114   the system will return an empty string.
115 
116+.. _start-alters-data-description:
117+
118 * Obviously, there can be side effects when calling some variables, and
119   it'd be either foolish or a security hole to allow the template system
120   to access them.
121diff --git a/tests/regressiontests/generic_views/base.py b/tests/regressiontests/generic_views/base.py
122index d9debb6..1e03577 100644
123--- a/tests/regressiontests/generic_views/base.py
124+++ b/tests/regressiontests/generic_views/base.py
125@@ -209,6 +209,14 @@ class TemplateViewTest(TestCase):
126         self.assertEqual(response.status_code, 200)
127         self.assertEqual(response.context['params'], {'foo': 'bar'})
128 
129+    def test_view_in_template_context(self):
130+        """
131+        A generic template view includes the 'view' in the context.
132+        """
133+        response = self.client.get('/template/simple/bar/')
134+        self.assertEqual(response.status_code, 200)
135+        self.assertTrue(isinstance(response.context['view'], View))
136+
137     def test_extra_template_params(self):
138         """
139         A template view can be customized to return extra context.
140diff --git a/tests/regressiontests/generic_views/detail.py b/tests/regressiontests/generic_views/detail.py
141index 0b5d873..10d0dbd 100644
142--- a/tests/regressiontests/generic_views/detail.py
143+++ b/tests/regressiontests/generic_views/detail.py
144@@ -2,6 +2,7 @@ from __future__ import absolute_import
145 
146 from django.core.exceptions import ImproperlyConfigured
147 from django.test import TestCase
148+from django.views.generic.base import View
149 
150 from .models import Artist, Author, Page
151 
152@@ -10,6 +11,10 @@ class DetailViewTest(TestCase):
153     fixtures = ['generic-views-test-data.json']
154     urls = 'regressiontests.generic_views.urls'
155 
156+    def test_view_in_template_context(self):
157+        res = self.client.get('/detail/obj/')
158+        self.assertTrue(isinstance(res.context['view'], View))
159+
160     def test_simple_object(self):
161         res = self.client.get('/detail/obj/')
162         self.assertEqual(res.status_code, 200)
163diff --git a/tests/regressiontests/generic_views/edit.py b/tests/regressiontests/generic_views/edit.py
164index 182615a..060b41a 100644
165--- a/tests/regressiontests/generic_views/edit.py
166+++ b/tests/regressiontests/generic_views/edit.py
167@@ -5,6 +5,7 @@ from django.core.urlresolvers import reverse
168 from django import forms
169 from django.test import TestCase
170 from django.utils.unittest import expectedFailure
171+from django.views.generic.base import View
172 
173 from . import views
174 from .models import Artist, Author
175@@ -92,6 +93,12 @@ class CreateViewTests(TestCase):
176         self.assertEqual(res.status_code, 302)
177         self.assertRedirects(res, 'http://testserver/accounts/login/?next=/edit/authors/create/restricted/')
178 
179+    def test_create_view_in_context(self):
180+        res = self.client.get('/edit/authors/create/')
181+        self.assertEqual(res.status_code, 200)
182+        self.assertTrue(isinstance(res.context['view'], View))
183+
184+
185 class UpdateViewTests(TestCase):
186     urls = 'regressiontests.generic_views.urls'
187 
188@@ -224,6 +231,16 @@ class UpdateViewTests(TestCase):
189         self.assertRedirects(res, 'http://testserver/list/authors/')
190         self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>'])
191 
192+    def test_update_view_in_context(self):
193+        a = Author.objects.create(
194+            name='Randall Munroe',
195+            slug='randall-munroe',
196+        )
197+        res = self.client.get('/edit/author/%d/update/' % a.pk)
198+        self.assertEqual(res.status_code, 200)
199+        self.assertTrue(isinstance(res.context['view'], View))
200+
201+
202 class DeleteViewTests(TestCase):
203     urls = 'regressiontests.generic_views.urls'
204 
205diff --git a/tests/regressiontests/generic_views/list.py b/tests/regressiontests/generic_views/list.py
206index 9ad00ed..d707b06 100644
207--- a/tests/regressiontests/generic_views/list.py
208+++ b/tests/regressiontests/generic_views/list.py
209@@ -2,6 +2,7 @@ from __future__ import absolute_import
210 
211 from django.core.exceptions import ImproperlyConfigured
212 from django.test import TestCase
213+from django.views.generic.base import View
214 
215 from .models import Author, Artist
216 
217@@ -159,6 +160,11 @@ class ListViewTests(TestCase):
218     def test_missing_items(self):
219         self.assertRaises(ImproperlyConfigured, self.client.get, '/list/authors/invalid/')
220 
221+    def test_view_in_context(self):
222+        res = self.client.get('/list/authors/')
223+        self.assertEqual(res.status_code, 200)
224+        self.assertTrue(isinstance(res.context['view'], View))
225+
226     def _make_authors(self, n):
227         Author.objects.all().delete()
228         for i in range(n):