Fixed #14878 -- Clarified the way verbose_name_plural is used in generic 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
This commit is contained in:
parent
2a5105ac15
commit
a00e8d4e42
|
@ -2,6 +2,7 @@ import re
|
|||
|
||||
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 @@ class SingleObjectMixin(object):
|
|||
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
|
||||
|
||||
|
|
|
@ -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 @@ class MultipleObjectMixin(object):
|
|||
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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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``.
|
||||
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.
|
||||
|
||||
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:
|
||||
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::
|
||||
|
||||
|
|
|
@ -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 @@ class DetailViewTest(TestCase):
|
|||
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)
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
[
|
||||
{
|
||||
"model": "generic_views.artist",
|
||||
"pk": 1,
|
||||
"fields": {
|
||||
"name": "Rene Magritte"
|
||||
}
|
||||
},
|
||||
{
|
||||
"model": "generic_views.author",
|
||||
"pk": 1,
|
||||
|
|
|
@ -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 @@ class ListViewTests(TestCase):
|
|||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -100,6 +100,9 @@ urlpatterns = patterns('',
|
|||
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"),
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in New Issue