diff --git a/django/views/generic/base.py b/django/views/generic/base.py
index ea14281..45e0a99 100644
a
|
b
|
class TemplateView(TemplateResponseMixin, View):
|
117 | 117 | """ |
118 | 118 | def get_context_data(self, **kwargs): |
119 | 119 | return { |
120 | | 'params': kwargs |
| 120 | 'params': kwargs, |
| 121 | 'view': self |
121 | 122 | } |
122 | 123 | |
123 | 124 | def get(self, request, *args, **kwargs): |
diff --git a/django/views/generic/detail.py b/django/views/generic/detail.py
index ab21573..6e84cb5 100644
a
|
b
|
class SingleObjectMixin(object):
|
87 | 87 | |
88 | 88 | def get_context_data(self, **kwargs): |
89 | 89 | context = kwargs |
| 90 | if 'view' not in context: |
| 91 | context['view'] = self |
90 | 92 | context_object_name = self.get_context_object_name(self.object) |
91 | 93 | if context_object_name: |
92 | 94 | context[context_object_name] = self.object |
diff --git a/django/views/generic/edit.py b/django/views/generic/edit.py
index 3cade52..6c53e27 100644
a
|
b
|
class FormMixin(object):
|
46 | 46 | return kwargs |
47 | 47 | |
48 | 48 | def get_context_data(self, **kwargs): |
| 49 | if 'view' not in kwargs: |
| 50 | kwargs['view'] = self |
49 | 51 | return kwargs |
50 | 52 | |
51 | 53 | def get_success_url(self): |
… |
… |
class ModelFormMixin(FormMixin, SingleObjectMixin):
|
90 | 92 | |
91 | 93 | def get_form_kwargs(self): |
92 | 94 | """ |
93 | | Returns the keyword arguments for instanciating the form. |
| 95 | Returns the keyword arguments for instantiating the form. |
94 | 96 | """ |
95 | 97 | kwargs = super(ModelFormMixin, self).get_form_kwargs() |
96 | 98 | kwargs.update({'instance': self.object}) |
… |
… |
class ModelFormMixin(FormMixin, SingleObjectMixin):
|
114 | 116 | |
115 | 117 | def get_context_data(self, **kwargs): |
116 | 118 | context = kwargs |
| 119 | if 'view' not in context: |
| 120 | context['view'] = self |
117 | 121 | if self.object: |
118 | 122 | context['object'] = self.object |
119 | 123 | context_object_name = self.get_context_object_name(self.object) |
diff --git a/django/views/generic/list.py b/django/views/generic/list.py
index 9797356..e04656a 100644
a
|
b
|
class MultipleObjectMixin(object):
|
94 | 94 | 'paginator': paginator, |
95 | 95 | 'page_obj': page, |
96 | 96 | 'is_paginated': is_paginated, |
97 | | 'object_list': queryset |
| 97 | 'object_list': queryset, |
| 98 | 'view': self |
98 | 99 | } |
99 | 100 | else: |
100 | 101 | context = { |
101 | 102 | 'paginator': None, |
102 | 103 | 'page_obj': None, |
103 | 104 | 'is_paginated': False, |
104 | | 'object_list': queryset |
| 105 | 'object_list': queryset, |
| 106 | 'view': self |
105 | 107 | } |
106 | 108 | context.update(kwargs) |
107 | 109 | if context_object_name is not None: |
diff --git a/docs/ref/class-based-views.txt b/docs/ref/class-based-views.txt
index 692417e..a851bf8 100644
a
|
b
|
View
|
879 | 879 | The default implementation returns ``HttpResponseNotAllowed`` with list |
880 | 880 | of allowed methods in plain text. |
881 | 881 | |
| 882 | **Context** |
| 883 | |
| 884 | .. versionadded:: 1.4 |
| 885 | |
| 886 | * ``view``: The template context of all class-based generic views will |
| 887 | include a ``view`` variable that points to the ``View`` instance. |
| 888 | |
| 889 | .. admonition:: Use ``alters_data`` where appropriate |
| 890 | |
| 891 | Note that having the view instance in the template context may expose |
| 892 | potentially hazardous methods to template authors. To prevent methods |
| 893 | like this from being called in the template, set ``alters_data=True`` |
| 894 | on those methods. For more information, the documention on |
| 895 | :ref:`rendering a template context <start-alters-data-description>`. |
| 896 | |
882 | 897 | TemplateView |
883 | 898 | ~~~~~~~~~~~~ |
884 | 899 | .. class:: TemplateView() |
diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
index 2b7d354..6bae4ef 100644
a
|
b
|
straight lookups. Here are some things to keep in mind:
|
195 | 195 | * A variable can only be called if it has no required arguments. Otherwise, |
196 | 196 | the system will return an empty string. |
197 | 197 | |
| 198 | .. _start-alters-data-description: |
| 199 | |
198 | 200 | * Obviously, there can be side effects when calling some variables, and |
199 | 201 | it'd be either foolish or a security hole to allow the template system |
200 | 202 | to access them. |
diff --git a/tests/regressiontests/generic_views/base.py b/tests/regressiontests/generic_views/base.py
index d9debb6..1e03577 100644
a
|
b
|
class TemplateViewTest(TestCase):
|
209 | 209 | self.assertEqual(response.status_code, 200) |
210 | 210 | self.assertEqual(response.context['params'], {'foo': 'bar'}) |
211 | 211 | |
| 212 | def test_view_in_template_context(self): |
| 213 | """ |
| 214 | A generic template view includes the 'view' in the context. |
| 215 | """ |
| 216 | response = self.client.get('/template/simple/bar/') |
| 217 | self.assertEqual(response.status_code, 200) |
| 218 | self.assertTrue(isinstance(response.context['view'], View)) |
| 219 | |
212 | 220 | def test_extra_template_params(self): |
213 | 221 | """ |
214 | 222 | A template view can be customized to return extra context. |
diff --git a/tests/regressiontests/generic_views/detail.py b/tests/regressiontests/generic_views/detail.py
index 0b5d873..10d0dbd 100644
a
|
b
|
from __future__ import absolute_import
|
2 | 2 | |
3 | 3 | from django.core.exceptions import ImproperlyConfigured |
4 | 4 | from django.test import TestCase |
| 5 | from django.views.generic.base import View |
5 | 6 | |
6 | 7 | from .models import Artist, Author, Page |
7 | 8 | |
… |
… |
class DetailViewTest(TestCase):
|
10 | 11 | fixtures = ['generic-views-test-data.json'] |
11 | 12 | urls = 'regressiontests.generic_views.urls' |
12 | 13 | |
| 14 | def test_view_in_template_context(self): |
| 15 | res = self.client.get('/detail/obj/') |
| 16 | self.assertTrue(isinstance(res.context['view'], View)) |
| 17 | |
13 | 18 | def test_simple_object(self): |
14 | 19 | res = self.client.get('/detail/obj/') |
15 | 20 | self.assertEqual(res.status_code, 200) |
diff --git a/tests/regressiontests/generic_views/edit.py b/tests/regressiontests/generic_views/edit.py
index 182615a..060b41a 100644
a
|
b
|
from django.core.urlresolvers import reverse
|
5 | 5 | from django import forms |
6 | 6 | from django.test import TestCase |
7 | 7 | from django.utils.unittest import expectedFailure |
| 8 | from django.views.generic.base import View |
8 | 9 | |
9 | 10 | from . import views |
10 | 11 | from .models import Artist, Author |
… |
… |
class CreateViewTests(TestCase):
|
92 | 93 | self.assertEqual(res.status_code, 302) |
93 | 94 | self.assertRedirects(res, 'http://testserver/accounts/login/?next=/edit/authors/create/restricted/') |
94 | 95 | |
| 96 | def test_create_view_in_context(self): |
| 97 | res = self.client.get('/edit/authors/create/') |
| 98 | self.assertEqual(res.status_code, 200) |
| 99 | self.assertTrue(isinstance(res.context['view'], View)) |
| 100 | |
| 101 | |
95 | 102 | class UpdateViewTests(TestCase): |
96 | 103 | urls = 'regressiontests.generic_views.urls' |
97 | 104 | |
… |
… |
class UpdateViewTests(TestCase):
|
224 | 231 | self.assertRedirects(res, 'http://testserver/list/authors/') |
225 | 232 | self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>']) |
226 | 233 | |
| 234 | def test_update_view_in_context(self): |
| 235 | a = Author.objects.create( |
| 236 | name='Randall Munroe', |
| 237 | slug='randall-munroe', |
| 238 | ) |
| 239 | res = self.client.get('/edit/author/%d/update/' % a.pk) |
| 240 | self.assertEqual(res.status_code, 200) |
| 241 | self.assertTrue(isinstance(res.context['view'], View)) |
| 242 | |
| 243 | |
227 | 244 | class DeleteViewTests(TestCase): |
228 | 245 | urls = 'regressiontests.generic_views.urls' |
229 | 246 | |
diff --git a/tests/regressiontests/generic_views/list.py b/tests/regressiontests/generic_views/list.py
index 9ad00ed..d707b06 100644
a
|
b
|
from __future__ import absolute_import
|
2 | 2 | |
3 | 3 | from django.core.exceptions import ImproperlyConfigured |
4 | 4 | from django.test import TestCase |
| 5 | from django.views.generic.base import View |
5 | 6 | |
6 | 7 | from .models import Author, Artist |
7 | 8 | |
… |
… |
class ListViewTests(TestCase):
|
159 | 160 | def test_missing_items(self): |
160 | 161 | self.assertRaises(ImproperlyConfigured, self.client.get, '/list/authors/invalid/') |
161 | 162 | |
| 163 | def test_view_in_context(self): |
| 164 | res = self.client.get('/list/authors/') |
| 165 | self.assertEqual(res.status_code, 200) |
| 166 | self.assertTrue(isinstance(res.context['view'], View)) |
| 167 | |
162 | 168 | def _make_authors(self, n): |
163 | 169 | Author.objects.all().delete() |
164 | 170 | for i in range(n): |