Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #14878 -- Clarified the way verbose_name_plural is used in gene…

…ric list views as a context variable. Thanks to diegueus9 for the report.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15133 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit a00e8d4e4204bfb730ba3eac2ee11ad83c8ec91b 1 parent 2a5105a
@freakboy3742 freakboy3742 authored
View
5 django/views/generic/detail.py
@@ -2,6 +2,7 @@
from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
from django.http import Http404
+from django.utils.encoding import smart_str
from django.views.generic.base import TemplateResponseMixin, View
@@ -79,8 +80,8 @@ def get_context_object_name(self, obj):
if self.context_object_name:
return self.context_object_name
elif hasattr(obj, '_meta'):
- return re.sub('[^a-zA-Z0-9]+', '_',
- obj._meta.verbose_name.lower())
+ return smart_str(re.sub('[^a-zA-Z0-9]+', '_',
+ obj._meta.verbose_name.lower()))
else:
return None
View
6 django/views/generic/list.py
@@ -1,9 +1,12 @@
+import re
+
from django.core.paginator import Paginator, InvalidPage
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404
from django.utils.encoding import smart_str
from django.views.generic.base import TemplateResponseMixin, View
+
class MultipleObjectMixin(object):
allow_empty = True
queryset = None
@@ -76,7 +79,8 @@ def get_context_object_name(self, object_list):
if self.context_object_name:
return self.context_object_name
elif hasattr(object_list, 'model'):
- return smart_str(object_list.model._meta.verbose_name_plural)
+ return smart_str(re.sub('[^a-zA-Z0-9]+', '_',
+ object_list.model._meta.verbose_name_plural.lower()))
else:
return None
View
2  docs/ref/class-based-views.txt
@@ -428,7 +428,7 @@ FormMixin
.. method:: get_form_kwargs()
Build the keyword arguments requried to instanciate an the form.
-
+
The ``initial`` argument is set to :meth:`.get_initial`. If the
request is a ``POST`` or ``PUT``, the request data (``request.POST``
and ``request.FILES``) will also be provided.
View
25 docs/topics/class-based-views.txt
@@ -206,14 +206,23 @@ their attributes or methods.
Making "friendly" template contexts
-----------------------------------
-You might have noticed that our sample publisher list template stores all the
-publishers in a variable named ``object_list``. While this works just fine, it
-isn't all that "friendly" to template authors: they have to "just know" that
-they're dealing with publishers here. A more obvious name for that variable
-would be ``publisher_list``.
-
-We can change the name of that variable easily with the ``context_object_name``
-attribute - here, we'll override it in the URLconf, since it's a simple change:
+You might have noticed that our sample publisher list template stores
+all the publishers in a variable named ``object_list``. While this
+works just fine, it isn't all that "friendly" to template authors:
+they have to "just know" that they're dealing with publishers here.
+
+Well, if you're dealing with a Django object, this is already done for
+you. When you are dealing with an object or queryset, Django is able
+to populate the context using the verbose name (or the plural verbose
+name, in the case of a list of objects) of the object being displayed.
+This is provided in addition to the default ``object_list`` entry, but
+contains exactly the same data.
+
+If the verbose name (or plural verbose name) still isn't a good match,
+you can manually set the name of the context variable. The
+``context_object_name`` attribute on a generic view specifies the
+context variable to use. In this example, we'll override it in the
+URLconf, since it's a simple change:
.. parsed-literal::
View
9 tests/regressiontests/generic_views/detail.py
@@ -1,7 +1,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
-from regressiontests.generic_views.models import Author, Page
+from regressiontests.generic_views.models import Artist, Author, Page
class DetailViewTest(TestCase):
@@ -28,6 +28,13 @@ def test_detail_by_slug(self):
self.assertEqual(res.context['author'], Author.objects.get(slug='scott-rosenberg'))
self.assertTemplateUsed(res, 'generic_views/author_detail.html')
+ def test_verbose_name(self):
+ res = self.client.get('/detail/artist/1/')
+ self.assertEqual(res.status_code, 200)
+ self.assertEqual(res.context['object'], Artist.objects.get(pk=1))
+ self.assertEqual(res.context['professional_artist'], Artist.objects.get(pk=1))
+ self.assertTemplateUsed(res, 'generic_views/artist_detail.html')
+
def test_template_name(self):
res = self.client.get('/detail/author/1/template_name/')
self.assertEqual(res.status_code, 200)
View
7 tests/regressiontests/generic_views/fixtures/generic-views-test-data.json
@@ -1,5 +1,12 @@
[
{
+ "model": "generic_views.artist",
+ "pk": 1,
+ "fields": {
+ "name": "Rene Magritte"
+ }
+ },
+ {
"model": "generic_views.author",
"pk": 1,
"fields": {
View
12 tests/regressiontests/generic_views/list.py
@@ -1,7 +1,7 @@
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
-from regressiontests.generic_views.models import Author
+from regressiontests.generic_views.models import Author, Artist
from regressiontests.generic_views.views import CustomPaginator
class ListViewTests(TestCase):
@@ -106,6 +106,16 @@ def test_paginated_non_queryset(self):
self.assertEqual(res.status_code, 200)
self.assertEqual(len(res.context['object_list']), 1)
+ def test_verbose_name(self):
+ res = self.client.get('/list/artists/')
+ self.assertEqual(res.status_code, 200)
+ self.assertTemplateUsed(res, 'generic_views/list.html')
+ self.assertEqual(list(res.context['object_list']), list(Artist.objects.all()))
+ self.assertIs(res.context['professional_artists'], res.context['object_list'])
+ self.assertIsNone(res.context['paginator'])
+ self.assertIsNone(res.context['page_obj'])
+ self.assertFalse(res.context['is_paginated'])
+
def test_allow_empty_false(self):
res = self.client.get('/list/authors/notempty/')
self.assertEqual(res.status_code, 200)
View
2  tests/regressiontests/generic_views/models.py
@@ -5,6 +5,8 @@ class Artist(models.Model):
class Meta:
ordering = ['name']
+ verbose_name = 'professional artist'
+ verbose_name_plural = 'professional artists'
def __unicode__(self):
return self.name
View
3  tests/regressiontests/generic_views/urls.py
@@ -100,6 +100,9 @@
views.DictList.as_view()),
(r'^list/dict/paginated/$',
views.DictList.as_view(paginate_by=1)),
+ url(r'^list/artists/$',
+ views.ArtistList.as_view(),
+ name="artists_list"),
url(r'^list/authors/$',
views.AuthorList.as_view(),
name="authors_list"),
View
5 tests/regressiontests/generic_views/views.py
@@ -47,6 +47,11 @@ class DictList(generic.ListView):
template_name = 'generic_views/list.html'
+class ArtistList(generic.ListView):
+ template_name = 'generic_views/list.html'
+ queryset = Artist.objects.all()
+
+
class AuthorList(generic.ListView):
queryset = Author.objects.all()
Please sign in to comment.
Something went wrong with that request. Please try again.