mirror of https://github.com/django/django.git
Fixed #15272 -- Altered generic views to use the guaranteed untranslated object_name, rather than the possibly translated verbose_name(_plural) for default context objects. Thanks to szczav for the report and patch.
This is BACKWARDS INCOMPATIBLE for anyone relying on the default context object names for class-based Detail and List views. To migrate, either update your templates to use the new default names, or add a context_object_name argument to your generic views. git-svn-id: http://code.djangoproject.com/svn/django/trunk@15531 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
a26034ffbf
commit
06b22963ea
|
@ -80,8 +80,7 @@ class SingleObjectMixin(object):
|
|||
if self.context_object_name:
|
||||
return self.context_object_name
|
||||
elif hasattr(obj, '_meta'):
|
||||
return smart_str(re.sub('[^a-zA-Z0-9]+', '_',
|
||||
obj._meta.verbose_name.lower()))
|
||||
return smart_str(obj._meta.object_name.lower())
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
|
@ -76,8 +76,7 @@ class MultipleObjectMixin(object):
|
|||
if self.context_object_name:
|
||||
return self.context_object_name
|
||||
elif hasattr(object_list, 'model'):
|
||||
return smart_str(re.sub('[^a-zA-Z0-9]+', '_',
|
||||
object_list.model._meta.verbose_name_plural.lower()))
|
||||
return smart_str('%s_list' % object_list.model._meta.object_name.lower())
|
||||
else:
|
||||
return None
|
||||
|
||||
|
|
|
@ -162,14 +162,14 @@ SingleObjectMixin
|
|||
it constructs a :class:`QuerySet` by calling the `all()` method on the
|
||||
:attr:`~SingleObjectMixin.model` attribute's default manager.
|
||||
|
||||
.. method:: get_context_object_name(object_list)
|
||||
.. method:: get_context_object_name(obj)
|
||||
|
||||
Return the context variable name that will be used to contain the
|
||||
list of data that this view is manipulating. If ``object_list`` is a
|
||||
:class:`QuerySet` of Django objects and
|
||||
data that this view is manipulating. If
|
||||
:attr:`~SingleObjectMixin.context_object_name` is not set, the context
|
||||
name will be constructed from the verbose plural name of the model that
|
||||
the queryset is composed from.
|
||||
name will be constructed from the ``object_name`` of the model that
|
||||
the queryset is composed from. For example, the model ``Article``
|
||||
would have context object named ``'article'``.
|
||||
|
||||
.. method:: get_context_data(**kwargs)
|
||||
|
||||
|
@ -333,10 +333,14 @@ MultipleObjectMixin
|
|||
|
||||
.. method:: get_context_object_name(object_list)
|
||||
|
||||
Return the context variable name that will be used to contain the list
|
||||
of data that this view is manipulating. If object_list is a queryset of
|
||||
Django objects, the context name will be verbose plural name of the
|
||||
model that the queryset is composed from.
|
||||
Return the context variable name that will be used to contain
|
||||
the list of data that this view is manipulating. If
|
||||
``object_list`` is a queryset of Django objects and
|
||||
:attr:`~MultipleObjectMixin.context_object_name` is not set,
|
||||
the context name will be the ``object_name`` of the model that
|
||||
the queryset is composed from, with postfix ``'_list'``
|
||||
appended. For example, the model ``Article`` would have a
|
||||
context object named ``article_list``.
|
||||
|
||||
.. method:: get_context_data(**kwargs)
|
||||
|
||||
|
|
|
@ -72,7 +72,8 @@ The ``_list`` suffix on list views
|
|||
In a function-based :class:`ListView`, the ``template_object_name``
|
||||
was appended with the suffix ``'_list'`` to yield the final context
|
||||
variable name. In a class-based ``ListView``, the
|
||||
``context_object_name`` is used verbatim.
|
||||
``context_object_name`` is used verbatim. The ``'_list'`` suffix
|
||||
is only applied when generating a default context object name.
|
||||
|
||||
The context data for ``object_list`` views
|
||||
------------------------------------------
|
||||
|
|
|
@ -92,7 +92,7 @@ class YearArchiveViewTests(TestCase):
|
|||
res = self.client.get('/dates/books/2006/make_object_list/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['date_list']), [datetime.datetime(2006, 5, 1)])
|
||||
self.assertEqual(list(res.context['books']), list(Book.objects.filter(pubdate__year=2006)))
|
||||
self.assertEqual(list(res.context['book_list']), list(Book.objects.filter(pubdate__year=2006)))
|
||||
self.assertEqual(list(res.context['object_list']), list(Book.objects.filter(pubdate__year=2006)))
|
||||
self.assertTemplateUsed(res, 'generic_views/book_archive_year.html')
|
||||
|
||||
|
@ -102,7 +102,7 @@ class YearArchiveViewTests(TestCase):
|
|||
res = self.client.get('/dates/books/1999/allow_empty/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['date_list']), [])
|
||||
self.assertEqual(list(res.context['books']), [])
|
||||
self.assertEqual(list(res.context['book_list']), [])
|
||||
|
||||
def test_year_view_allow_future(self):
|
||||
# Create a new book in the future
|
||||
|
@ -113,7 +113,7 @@ class YearArchiveViewTests(TestCase):
|
|||
|
||||
res = self.client.get('/dates/books/%s/allow_empty/' % year)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['books']), [])
|
||||
self.assertEqual(list(res.context['book_list']), [])
|
||||
|
||||
res = self.client.get('/dates/books/%s/allow_future/' % year)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
|
@ -132,7 +132,7 @@ class MonthArchiveViewTests(TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/book_archive_month.html')
|
||||
self.assertEqual(list(res.context['date_list']), [datetime.datetime(2008, 10, 1)])
|
||||
self.assertEqual(list(res.context['books']),
|
||||
self.assertEqual(list(res.context['book_list']),
|
||||
list(Book.objects.filter(pubdate=datetime.date(2008, 10, 1))))
|
||||
self.assertEqual(res.context['month'], datetime.date(2008, 10, 1))
|
||||
|
||||
|
@ -149,7 +149,7 @@ class MonthArchiveViewTests(TestCase):
|
|||
res = self.client.get('/dates/books/2000/jan/allow_empty/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['date_list']), [])
|
||||
self.assertEqual(list(res.context['books']), [])
|
||||
self.assertEqual(list(res.context['book_list']), [])
|
||||
self.assertEqual(res.context['month'], datetime.date(2000, 1, 1))
|
||||
|
||||
# Since it's allow empty, next/prev are allowed to be empty months (#7164)
|
||||
|
@ -175,7 +175,7 @@ class MonthArchiveViewTests(TestCase):
|
|||
res = self.client.get('/dates/books/%s/allow_future/' % urlbit)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(res.context['date_list'][0].date(), b.pubdate)
|
||||
self.assertEqual(list(res.context['books']), [b])
|
||||
self.assertEqual(list(res.context['book_list']), [b])
|
||||
self.assertEqual(res.context['month'], future)
|
||||
|
||||
# Since it's allow_future but not allow_empty, next/prev are not
|
||||
|
@ -229,7 +229,7 @@ class WeekArchiveViewTests(TestCase):
|
|||
res = self.client.get('/dates/books/2008/week/39/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/book_archive_week.html')
|
||||
self.assertEqual(res.context['books'][0], Book.objects.get(pubdate=datetime.date(2008, 10, 1)))
|
||||
self.assertEqual(res.context['book_list'][0], Book.objects.get(pubdate=datetime.date(2008, 10, 1)))
|
||||
self.assertEqual(res.context['week'], datetime.date(2008, 9, 28))
|
||||
|
||||
def test_week_view_allow_empty(self):
|
||||
|
@ -238,7 +238,7 @@ class WeekArchiveViewTests(TestCase):
|
|||
|
||||
res = self.client.get('/dates/books/2008/week/12/allow_empty/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['books']), [])
|
||||
self.assertEqual(list(res.context['book_list']), [])
|
||||
|
||||
def test_week_view_allow_future(self):
|
||||
future = datetime.date(datetime.date.today().year + 1, 1, 1)
|
||||
|
@ -249,7 +249,7 @@ class WeekArchiveViewTests(TestCase):
|
|||
|
||||
res = self.client.get('/dates/books/%s/week/1/allow_future/' % future.year)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['books']), [b])
|
||||
self.assertEqual(list(res.context['book_list']), [b])
|
||||
|
||||
def test_week_view_invalid_pattern(self):
|
||||
res = self.client.get('/dates/books/2007/week/no_week/')
|
||||
|
@ -273,7 +273,7 @@ class DayArchiveViewTests(TestCase):
|
|||
res = self.client.get('/dates/books/2008/oct/01/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/book_archive_day.html')
|
||||
self.assertEqual(list(res.context['books']),
|
||||
self.assertEqual(list(res.context['book_list']),
|
||||
list(Book.objects.filter(pubdate=datetime.date(2008, 10, 1))))
|
||||
self.assertEqual(res.context['day'], datetime.date(2008, 10, 1))
|
||||
|
||||
|
@ -289,7 +289,7 @@ class DayArchiveViewTests(TestCase):
|
|||
# allow_empty = True, empty month
|
||||
res = self.client.get('/dates/books/2000/jan/1/allow_empty/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['books']), [])
|
||||
self.assertEqual(list(res.context['book_list']), [])
|
||||
self.assertEqual(res.context['day'], datetime.date(2000, 1, 1))
|
||||
|
||||
# Since it's allow empty, next/prev are allowed to be empty months (#7164)
|
||||
|
@ -314,7 +314,7 @@ class DayArchiveViewTests(TestCase):
|
|||
# allow_future = True, valid future month
|
||||
res = self.client.get('/dates/books/%s/allow_future/' % urlbit)
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['books']), [b])
|
||||
self.assertEqual(list(res.context['book_list']), [b])
|
||||
self.assertEqual(res.context['day'], future)
|
||||
|
||||
# allow_future but not allow_empty, next/prev amust be valid
|
||||
|
|
|
@ -32,7 +32,7 @@ class DetailViewTest(TestCase):
|
|||
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.assertEqual(res.context['artist'], Artist.objects.get(pk=1))
|
||||
self.assertTemplateUsed(res, 'generic_views/artist_detail.html')
|
||||
|
||||
def test_template_name(self):
|
||||
|
|
|
@ -19,7 +19,7 @@ class ListViewTests(TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/author_list.html')
|
||||
self.assertEqual(list(res.context['object_list']), list(Author.objects.all()))
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertIsNone(res.context['paginator'])
|
||||
self.assertIsNone(res.context['page_obj'])
|
||||
self.assertFalse(res.context['is_paginated'])
|
||||
|
@ -30,12 +30,12 @@ class ListViewTests(TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/author_list.html')
|
||||
self.assertEqual(len(res.context['object_list']), 30)
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertTrue(res.context['is_paginated'])
|
||||
self.assertEqual(res.context['page_obj'].number, 1)
|
||||
self.assertEqual(res.context['paginator'].num_pages, 4)
|
||||
self.assertEqual(res.context['authors'][0].name, 'Author 00')
|
||||
self.assertEqual(list(res.context['authors'])[-1].name, 'Author 29')
|
||||
self.assertEqual(res.context['author_list'][0].name, 'Author 00')
|
||||
self.assertEqual(list(res.context['author_list'])[-1].name, 'Author 29')
|
||||
|
||||
def test_paginated_queryset_shortdata(self):
|
||||
# Test that short datasets ALSO result in a paginated view.
|
||||
|
@ -43,7 +43,7 @@ class ListViewTests(TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/author_list.html')
|
||||
self.assertEqual(list(res.context['object_list']), list(Author.objects.all()))
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertEqual(res.context['page_obj'].number, 1)
|
||||
self.assertEqual(res.context['paginator'].num_pages, 1)
|
||||
self.assertTrue(res.context['is_paginated'])
|
||||
|
@ -54,8 +54,8 @@ class ListViewTests(TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/author_list.html')
|
||||
self.assertEqual(len(res.context['object_list']), 30)
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertEqual(res.context['authors'][0].name, 'Author 30')
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertEqual(res.context['author_list'][0].name, 'Author 30')
|
||||
self.assertEqual(res.context['page_obj'].number, 2)
|
||||
|
||||
def test_paginated_get_last_page_by_query_string(self):
|
||||
|
@ -63,8 +63,8 @@ class ListViewTests(TestCase):
|
|||
res = self.client.get('/list/authors/paginated/', {'page': 'last'})
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(len(res.context['object_list']), 10)
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertEqual(res.context['authors'][0].name, 'Author 90')
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertEqual(res.context['author_list'][0].name, 'Author 90')
|
||||
self.assertEqual(res.context['page_obj'].number, 4)
|
||||
|
||||
def test_paginated_get_page_by_urlvar(self):
|
||||
|
@ -73,8 +73,8 @@ class ListViewTests(TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'generic_views/author_list.html')
|
||||
self.assertEqual(len(res.context['object_list']), 30)
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertEqual(res.context['authors'][0].name, 'Author 60')
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertEqual(res.context['author_list'][0].name, 'Author 60')
|
||||
self.assertEqual(res.context['page_obj'].number, 3)
|
||||
|
||||
def test_paginated_page_out_of_range(self):
|
||||
|
@ -112,7 +112,7 @@ class ListViewTests(TestCase):
|
|||
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.assertIs(res.context['artist_list'], res.context['object_list'])
|
||||
self.assertIsNone(res.context['paginator'])
|
||||
self.assertIsNone(res.context['page_obj'])
|
||||
self.assertFalse(res.context['is_paginated'])
|
||||
|
@ -128,14 +128,14 @@ class ListViewTests(TestCase):
|
|||
res = self.client.get('/list/authors/template_name/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['object_list']), list(Author.objects.all()))
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertTemplateUsed(res, 'generic_views/list.html')
|
||||
|
||||
def test_template_name_suffix(self):
|
||||
res = self.client.get('/list/authors/template_name_suffix/')
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertEqual(list(res.context['object_list']), list(Author.objects.all()))
|
||||
self.assertIs(res.context['authors'], res.context['object_list'])
|
||||
self.assertIs(res.context['author_list'], res.context['object_list'])
|
||||
self.assertTemplateUsed(res, 'generic_views/author_objects.html')
|
||||
|
||||
def test_context_object_name(self):
|
||||
|
|
Loading…
Reference in New Issue