Fixed #16744 -- Class based view should have the view object in the context

Updated the most recent patch from @claudep to apply again and updated
the documentation location.
This commit is contained in:
Marc Tamlyn 2012-08-18 14:46:17 +01:00 committed by Andrew Godwin
parent 547b181046
commit 58683e9c82
8 changed files with 35 additions and 2 deletions

View File

@ -18,6 +18,8 @@ class ContextMixin(object):
""" """
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
if 'view' not in kwargs:
kwargs['view'] = self
return kwargs return kwargs

View File

@ -17,8 +17,20 @@ ContextMixin
.. method:: get_context_data(**kwargs) .. method:: get_context_data(**kwargs)
Returns a dictionary representing the template context. The Returns a dictionary representing the template context. The keyword
keyword arguments provided will make up the returned context. arguments provided will make up the returned context.
The template context of all class-based generic views include a
``view`` variable that points to the ``View`` instance.
.. admonition:: Use ``alters_data`` where appropriate
Note that having the view instance in the template context may
expose potentially hazardous methods to template authors. To
prevent methods like this from being called in the template, set
``alters_data=True`` on those methods. For more information, read
the documentation on :ref:`rendering a template context
<alters-data-description>`.
TemplateResponseMixin TemplateResponseMixin
--------------------- ---------------------

View File

@ -198,6 +198,8 @@ straight lookups. Here are some things to keep in mind:
* A variable can only be called if it has no required arguments. Otherwise, * A variable can only be called if it has no required arguments. Otherwise,
the system will return an empty string. the system will return an empty string.
.. _alters-data-description:
* Obviously, there can be side effects when calling some variables, and * Obviously, there can be side effects when calling some variables, and
it'd be either foolish or a security hole to allow the template system it'd be either foolish or a security hole to allow the template system
to access them. to access them.

View File

@ -84,6 +84,12 @@ By passing ``False`` using this argument it is now possible to retreive the
:class:`ContentType <django.contrib.contenttypes.models.ContentType>` :class:`ContentType <django.contrib.contenttypes.models.ContentType>`
associated with proxy models. associated with proxy models.
New ``view`` variable in class-based views context
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In all :doc:`generic class-based views </topics/class-based-views/index>`
(or any class-based view inheriting from ``ContextMixin``), the context dictionary
contains a ``view`` variable that points to the ``View`` instance.
Minor features Minor features
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

View File

@ -276,6 +276,7 @@ class TemplateViewTest(TestCase):
response = self.client.get('/template/simple/bar/') response = self.client.get('/template/simple/bar/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['params'], {'foo': 'bar'}) self.assertEqual(response.context['params'], {'foo': 'bar'})
self.assertTrue(isinstance(response.context['view'], View))
def test_extra_template_params(self): def test_extra_template_params(self):
""" """
@ -285,6 +286,7 @@ class TemplateViewTest(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.context['params'], {'foo': 'bar'}) self.assertEqual(response.context['params'], {'foo': 'bar'})
self.assertEqual(response.context['key'], 'value') self.assertEqual(response.context['key'], 'value')
self.assertTrue(isinstance(response.context['view'], View))
def test_cached_views(self): def test_cached_views(self):
""" """

View File

@ -2,6 +2,7 @@ from __future__ import absolute_import
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase from django.test import TestCase
from django.views.generic.base import View
from .models import Artist, Author, Page from .models import Artist, Author, Page
@ -14,6 +15,7 @@ class DetailViewTest(TestCase):
res = self.client.get('/detail/obj/') res = self.client.get('/detail/obj/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertEqual(res.context['object'], {'foo': 'bar'}) self.assertEqual(res.context['object'], {'foo': 'bar'})
self.assertTrue(isinstance(res.context['view'], View))
self.assertTemplateUsed(res, 'generic_views/detail.html') self.assertTemplateUsed(res, 'generic_views/detail.html')
def test_detail_by_pk(self): def test_detail_by_pk(self):

View File

@ -5,6 +5,7 @@ from django.core.urlresolvers import reverse
from django import forms from django import forms
from django.test import TestCase from django.test import TestCase
from django.utils.unittest import expectedFailure from django.utils.unittest import expectedFailure
from django.views.generic.base import View
from django.views.generic.edit import FormMixin from django.views.generic.edit import FormMixin
from . import views from . import views
@ -31,6 +32,7 @@ class CreateViewTests(TestCase):
res = self.client.get('/edit/authors/create/') res = self.client.get('/edit/authors/create/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTrue(isinstance(res.context['form'], forms.ModelForm)) self.assertTrue(isinstance(res.context['form'], forms.ModelForm))
self.assertTrue(isinstance(res.context['view'], View))
self.assertFalse('object' in res.context) self.assertFalse('object' in res.context)
self.assertFalse('author' in res.context) self.assertFalse('author' in res.context)
self.assertTemplateUsed(res, 'generic_views/author_form.html') self.assertTemplateUsed(res, 'generic_views/author_form.html')
@ -101,6 +103,7 @@ class CreateViewTests(TestCase):
self.assertEqual(res.status_code, 302) self.assertEqual(res.status_code, 302)
self.assertRedirects(res, 'http://testserver/accounts/login/?next=/edit/authors/create/restricted/') self.assertRedirects(res, 'http://testserver/accounts/login/?next=/edit/authors/create/restricted/')
class UpdateViewTests(TestCase): class UpdateViewTests(TestCase):
urls = 'regressiontests.generic_views.urls' urls = 'regressiontests.generic_views.urls'
@ -226,6 +229,7 @@ class UpdateViewTests(TestCase):
res = self.client.get('/edit/author/update/') res = self.client.get('/edit/author/update/')
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTrue(isinstance(res.context['form'], forms.ModelForm)) self.assertTrue(isinstance(res.context['form'], forms.ModelForm))
self.assertTrue(isinstance(res.context['view'], View))
self.assertEqual(res.context['object'], Author.objects.get(pk=a.pk)) self.assertEqual(res.context['object'], Author.objects.get(pk=a.pk))
self.assertEqual(res.context['author'], Author.objects.get(pk=a.pk)) self.assertEqual(res.context['author'], Author.objects.get(pk=a.pk))
self.assertTemplateUsed(res, 'generic_views/author_form.html') self.assertTemplateUsed(res, 'generic_views/author_form.html')
@ -237,6 +241,7 @@ class UpdateViewTests(TestCase):
self.assertRedirects(res, 'http://testserver/list/authors/') self.assertRedirects(res, 'http://testserver/list/authors/')
self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>']) self.assertQuerysetEqual(Author.objects.all(), ['<Author: Randall Munroe (xkcd)>'])
class DeleteViewTests(TestCase): class DeleteViewTests(TestCase):
urls = 'regressiontests.generic_views.urls' urls = 'regressiontests.generic_views.urls'

View File

@ -2,6 +2,7 @@ from __future__ import absolute_import
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase from django.test import TestCase
from django.views.generic.base import View
from .models import Author, Artist from .models import Author, Artist
@ -21,6 +22,7 @@ class ListViewTests(TestCase):
self.assertEqual(res.status_code, 200) self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'generic_views/author_list.html') self.assertTemplateUsed(res, 'generic_views/author_list.html')
self.assertEqual(list(res.context['object_list']), list(Author.objects.all())) self.assertEqual(list(res.context['object_list']), list(Author.objects.all()))
self.assertTrue(isinstance(res.context['view'], View))
self.assertIs(res.context['author_list'], res.context['object_list']) self.assertIs(res.context['author_list'], res.context['object_list'])
self.assertIsNone(res.context['paginator']) self.assertIsNone(res.context['paginator'])
self.assertIsNone(res.context['page_obj']) self.assertIsNone(res.context['page_obj'])