diff --git a/django/views/generic/detail.py b/django/views/generic/detail.py index 3fc21c1f49..dafdbe87b3 100644 --- a/django/views/generic/detail.py +++ b/django/views/generic/detail.py @@ -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 diff --git a/django/views/generic/list.py b/django/views/generic/list.py index 9f1c8aab29..213b89b64d 100644 --- a/django/views/generic/list.py +++ b/django/views/generic/list.py @@ -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 diff --git a/docs/ref/class-based-views.txt b/docs/ref/class-based-views.txt index 8350fd22b2..09ad0d3cec 100644 --- a/docs/ref/class-based-views.txt +++ b/docs/ref/class-based-views.txt @@ -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) diff --git a/docs/topics/generic-views-migration.txt b/docs/topics/generic-views-migration.txt index ab6b87e6d1..fa62f5de1f 100644 --- a/docs/topics/generic-views-migration.txt +++ b/docs/topics/generic-views-migration.txt @@ -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 ------------------------------------------ diff --git a/tests/regressiontests/generic_views/dates.py b/tests/regressiontests/generic_views/dates.py index aa453ba2f2..d5345befd0 100644 --- a/tests/regressiontests/generic_views/dates.py +++ b/tests/regressiontests/generic_views/dates.py @@ -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 diff --git a/tests/regressiontests/generic_views/detail.py b/tests/regressiontests/generic_views/detail.py index c26ca67bd1..e8f2050fe2 100644 --- a/tests/regressiontests/generic_views/detail.py +++ b/tests/regressiontests/generic_views/detail.py @@ -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): diff --git a/tests/regressiontests/generic_views/list.py b/tests/regressiontests/generic_views/list.py index de7302048b..b784f4d659 100644 --- a/tests/regressiontests/generic_views/list.py +++ b/tests/regressiontests/generic_views/list.py @@ -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):