Loading django/views/generic/dates.py +3 −3 Original line number Diff line number Diff line Loading @@ -377,7 +377,7 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View): """ return self.date_list_period def get_date_list(self, queryset, date_type=None): def get_date_list(self, queryset, date_type=None, ordering='ASC'): """ Get a date list by calling `queryset.dates()`, checking along the way for empty lists that aren't allowed. Loading @@ -387,7 +387,7 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View): if date_type is None: date_type = self.get_date_list_period() date_list = queryset.dates(date_field, date_type)[::-1] date_list = queryset.dates(date_field, date_type, ordering) if date_list is not None and not date_list and not allow_empty: name = force_text(queryset.model._meta.verbose_name_plural) raise Http404(_("No %(verbose_name_plural)s available") % Loading @@ -409,7 +409,7 @@ class BaseArchiveIndexView(BaseDateListView): Return (date_list, items, extra_context) for this request. """ qs = self.get_dated_queryset(ordering='-%s' % self.get_date_field()) date_list = self.get_date_list(qs) date_list = self.get_date_list(qs, ordering='DESC') if not date_list: qs = qs.none() Loading docs/ref/class-based-views/mixins-date-based.txt +8 −4 Original line number Diff line number Diff line Loading @@ -318,12 +318,16 @@ BaseDateListView Returns the aggregation period for ``date_list``. Returns :attr:`~BaseDateListView.date_list_period` by default. .. method:: get_date_list(queryset, date_type=None) .. method:: get_date_list(queryset, date_type=None, ordering='ASC') Returns the list of dates of type ``date_type`` for which ``queryset`` contains entries. For example, ``get_date_list(qs, 'year')`` will return the list of years for which ``qs`` has entries. If ``date_type`` isn't provided, the result of :meth:`BaseDateListView.get_date_list_period` is used. See :meth:`~django.db.models.query.QuerySet.dates()` for the ways that the ``date_type`` argument can be used. :meth:`~BaseDateListView.get_date_list_period` is used. ``date_type`` and ``ordering`` are simply passed to :meth:`QuerySet.dates()<django.db.models.query.QuerySet.dates>`. .. versionchanged:: 1.5 The ``ordering`` parameter was added, and the default order was changed to ascending. docs/releases/1.5.txt +15 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,21 @@ year|date:"Y" }}``. ``next_year`` and ``previous_year`` were also added in the context. They are calculated according to ``allow_empty`` and ``allow_future``. Context in year and month archive class-based views ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :class:`~django.views.generic.dates.YearArchiveView` and :class:`~django.views.generic.dates.MonthArchiveView` were documented to provide a ``date_list`` sorted in ascending order in the context, like their function-based predecessors, but it actually was in descending order. In 1.5, the documented order was restored. You may want to add (or remove) the ``reversed`` keyword when you're iterating on ``date_list`` in a template:: {% for date in date_list reversed %} :class:`~django.views.generic.dates.ArchiveIndexView` still provides a ``date_list`` in descending order. Context in TemplateView ~~~~~~~~~~~~~~~~~~~~~~~ Loading tests/regressiontests/generic_views/dates.py +35 −15 Original line number Diff line number Diff line Loading @@ -23,29 +23,30 @@ requires_tz_support = skipUnless(TZ_SUPPORT, "time zone, but your operating system isn't able to do that.") class ArchiveIndexViewTests(TestCase): fixtures = ['generic-views-test-data.json'] urls = 'regressiontests.generic_views.urls' def _make_books(self, n, base_date): def _make_books(n, base_date): for i in range(n): b = Book.objects.create( name='Book %d' % i, slug='book-%d' % i, pages=100+i, pubdate=base_date - datetime.timedelta(days=1)) pubdate=base_date - datetime.timedelta(days=i)) class ArchiveIndexViewTests(TestCase): fixtures = ['generic-views-test-data.json'] urls = 'regressiontests.generic_views.urls' def test_archive_view(self): res = self.client.get('/dates/books/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all())) self.assertTemplateUsed(res, 'generic_views/book_archive.html') def test_archive_view_context_object_name(self): res = self.client.get('/dates/books/context_object_name/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['thingies']), list(Book.objects.all())) self.assertFalse('latest' in res.context) self.assertTemplateUsed(res, 'generic_views/book_archive.html') Loading @@ -65,14 +66,14 @@ class ArchiveIndexViewTests(TestCase): def test_archive_view_template(self): res = self.client.get('/dates/books/template_name/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all())) self.assertTemplateUsed(res, 'generic_views/list.html') def test_archive_view_template_suffix(self): res = self.client.get('/dates/books/template_name_suffix/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all())) self.assertTemplateUsed(res, 'generic_views/book_detail.html') Loading @@ -82,13 +83,13 @@ class ArchiveIndexViewTests(TestCase): def test_archive_view_by_month(self): res = self.client.get('/dates/books/by_month/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'month')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'month', 'DESC'))) def test_paginated_archive_view(self): self._make_books(20, base_date=datetime.date.today()) _make_books(20, base_date=datetime.date.today()) res = self.client.get('/dates/books/paginated/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all()[0:10])) self.assertTemplateUsed(res, 'generic_views/book_archive.html') Loading @@ -99,7 +100,7 @@ class ArchiveIndexViewTests(TestCase): def test_paginated_archive_view_does_not_load_entire_table(self): # Regression test for #18087 self._make_books(20, base_date=datetime.date.today()) _make_books(20, base_date=datetime.date.today()) # 1 query for years list + 1 query for books with self.assertNumQueries(2): self.client.get('/dates/books/') Loading @@ -124,6 +125,13 @@ class ArchiveIndexViewTests(TestCase): res = self.client.get('/dates/booksignings/') self.assertEqual(res.status_code, 200) def test_date_list_order(self): """date_list should be sorted descending in index""" _make_books(5, base_date=datetime.date(2011, 12, 25)) res = self.client.get('/dates/books/') self.assertEqual(res.status_code, 200) self.assertEqual(list(res.context['date_list']), list(reversed(sorted(res.context['date_list'])))) class YearArchiveViewTests(TestCase): fixtures = ['generic-views-test-data.json'] Loading Loading @@ -202,6 +210,12 @@ class YearArchiveViewTests(TestCase): res = self.client.get('/dates/booksignings/2008/') self.assertEqual(res.status_code, 200) def test_date_list_order(self): """date_list should be sorted ascending in year view""" _make_books(10, base_date=datetime.date(2011, 12, 25)) res = self.client.get('/dates/books/2011/') self.assertEqual(list(res.context['date_list']), list(sorted(res.context['date_list']))) class MonthArchiveViewTests(TestCase): fixtures = ['generic-views-test-data.json'] Loading Loading @@ -322,6 +336,12 @@ class MonthArchiveViewTests(TestCase): res = self.client.get('/dates/booksignings/2008/apr/') self.assertEqual(res.status_code, 200) def test_date_list_order(self): """date_list should be sorted ascending in month view""" _make_books(10, base_date=datetime.date(2011, 12, 25)) res = self.client.get('/dates/books/2011/dec/') self.assertEqual(list(res.context['date_list']), list(sorted(res.context['date_list']))) class WeekArchiveViewTests(TestCase): fixtures = ['generic-views-test-data.json'] Loading Loading
django/views/generic/dates.py +3 −3 Original line number Diff line number Diff line Loading @@ -377,7 +377,7 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View): """ return self.date_list_period def get_date_list(self, queryset, date_type=None): def get_date_list(self, queryset, date_type=None, ordering='ASC'): """ Get a date list by calling `queryset.dates()`, checking along the way for empty lists that aren't allowed. Loading @@ -387,7 +387,7 @@ class BaseDateListView(MultipleObjectMixin, DateMixin, View): if date_type is None: date_type = self.get_date_list_period() date_list = queryset.dates(date_field, date_type)[::-1] date_list = queryset.dates(date_field, date_type, ordering) if date_list is not None and not date_list and not allow_empty: name = force_text(queryset.model._meta.verbose_name_plural) raise Http404(_("No %(verbose_name_plural)s available") % Loading @@ -409,7 +409,7 @@ class BaseArchiveIndexView(BaseDateListView): Return (date_list, items, extra_context) for this request. """ qs = self.get_dated_queryset(ordering='-%s' % self.get_date_field()) date_list = self.get_date_list(qs) date_list = self.get_date_list(qs, ordering='DESC') if not date_list: qs = qs.none() Loading
docs/ref/class-based-views/mixins-date-based.txt +8 −4 Original line number Diff line number Diff line Loading @@ -318,12 +318,16 @@ BaseDateListView Returns the aggregation period for ``date_list``. Returns :attr:`~BaseDateListView.date_list_period` by default. .. method:: get_date_list(queryset, date_type=None) .. method:: get_date_list(queryset, date_type=None, ordering='ASC') Returns the list of dates of type ``date_type`` for which ``queryset`` contains entries. For example, ``get_date_list(qs, 'year')`` will return the list of years for which ``qs`` has entries. If ``date_type`` isn't provided, the result of :meth:`BaseDateListView.get_date_list_period` is used. See :meth:`~django.db.models.query.QuerySet.dates()` for the ways that the ``date_type`` argument can be used. :meth:`~BaseDateListView.get_date_list_period` is used. ``date_type`` and ``ordering`` are simply passed to :meth:`QuerySet.dates()<django.db.models.query.QuerySet.dates>`. .. versionchanged:: 1.5 The ``ordering`` parameter was added, and the default order was changed to ascending.
docs/releases/1.5.txt +15 −0 Original line number Diff line number Diff line Loading @@ -152,6 +152,21 @@ year|date:"Y" }}``. ``next_year`` and ``previous_year`` were also added in the context. They are calculated according to ``allow_empty`` and ``allow_future``. Context in year and month archive class-based views ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :class:`~django.views.generic.dates.YearArchiveView` and :class:`~django.views.generic.dates.MonthArchiveView` were documented to provide a ``date_list`` sorted in ascending order in the context, like their function-based predecessors, but it actually was in descending order. In 1.5, the documented order was restored. You may want to add (or remove) the ``reversed`` keyword when you're iterating on ``date_list`` in a template:: {% for date in date_list reversed %} :class:`~django.views.generic.dates.ArchiveIndexView` still provides a ``date_list`` in descending order. Context in TemplateView ~~~~~~~~~~~~~~~~~~~~~~~ Loading
tests/regressiontests/generic_views/dates.py +35 −15 Original line number Diff line number Diff line Loading @@ -23,29 +23,30 @@ requires_tz_support = skipUnless(TZ_SUPPORT, "time zone, but your operating system isn't able to do that.") class ArchiveIndexViewTests(TestCase): fixtures = ['generic-views-test-data.json'] urls = 'regressiontests.generic_views.urls' def _make_books(self, n, base_date): def _make_books(n, base_date): for i in range(n): b = Book.objects.create( name='Book %d' % i, slug='book-%d' % i, pages=100+i, pubdate=base_date - datetime.timedelta(days=1)) pubdate=base_date - datetime.timedelta(days=i)) class ArchiveIndexViewTests(TestCase): fixtures = ['generic-views-test-data.json'] urls = 'regressiontests.generic_views.urls' def test_archive_view(self): res = self.client.get('/dates/books/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all())) self.assertTemplateUsed(res, 'generic_views/book_archive.html') def test_archive_view_context_object_name(self): res = self.client.get('/dates/books/context_object_name/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['thingies']), list(Book.objects.all())) self.assertFalse('latest' in res.context) self.assertTemplateUsed(res, 'generic_views/book_archive.html') Loading @@ -65,14 +66,14 @@ class ArchiveIndexViewTests(TestCase): def test_archive_view_template(self): res = self.client.get('/dates/books/template_name/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all())) self.assertTemplateUsed(res, 'generic_views/list.html') def test_archive_view_template_suffix(self): res = self.client.get('/dates/books/template_name_suffix/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all())) self.assertTemplateUsed(res, 'generic_views/book_detail.html') Loading @@ -82,13 +83,13 @@ class ArchiveIndexViewTests(TestCase): def test_archive_view_by_month(self): res = self.client.get('/dates/books/by_month/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'month')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'month', 'DESC'))) def test_paginated_archive_view(self): self._make_books(20, base_date=datetime.date.today()) _make_books(20, base_date=datetime.date.today()) res = self.client.get('/dates/books/paginated/') self.assertEqual(res.status_code, 200) self.assertEqual(res.context['date_list'], Book.objects.dates('pubdate', 'year')[::-1]) self.assertEqual(list(res.context['date_list']), list(Book.objects.dates('pubdate', 'year', 'DESC'))) self.assertEqual(list(res.context['latest']), list(Book.objects.all()[0:10])) self.assertTemplateUsed(res, 'generic_views/book_archive.html') Loading @@ -99,7 +100,7 @@ class ArchiveIndexViewTests(TestCase): def test_paginated_archive_view_does_not_load_entire_table(self): # Regression test for #18087 self._make_books(20, base_date=datetime.date.today()) _make_books(20, base_date=datetime.date.today()) # 1 query for years list + 1 query for books with self.assertNumQueries(2): self.client.get('/dates/books/') Loading @@ -124,6 +125,13 @@ class ArchiveIndexViewTests(TestCase): res = self.client.get('/dates/booksignings/') self.assertEqual(res.status_code, 200) def test_date_list_order(self): """date_list should be sorted descending in index""" _make_books(5, base_date=datetime.date(2011, 12, 25)) res = self.client.get('/dates/books/') self.assertEqual(res.status_code, 200) self.assertEqual(list(res.context['date_list']), list(reversed(sorted(res.context['date_list'])))) class YearArchiveViewTests(TestCase): fixtures = ['generic-views-test-data.json'] Loading Loading @@ -202,6 +210,12 @@ class YearArchiveViewTests(TestCase): res = self.client.get('/dates/booksignings/2008/') self.assertEqual(res.status_code, 200) def test_date_list_order(self): """date_list should be sorted ascending in year view""" _make_books(10, base_date=datetime.date(2011, 12, 25)) res = self.client.get('/dates/books/2011/') self.assertEqual(list(res.context['date_list']), list(sorted(res.context['date_list']))) class MonthArchiveViewTests(TestCase): fixtures = ['generic-views-test-data.json'] Loading Loading @@ -322,6 +336,12 @@ class MonthArchiveViewTests(TestCase): res = self.client.get('/dates/booksignings/2008/apr/') self.assertEqual(res.status_code, 200) def test_date_list_order(self): """date_list should be sorted ascending in month view""" _make_books(10, base_date=datetime.date(2011, 12, 25)) res = self.client.get('/dates/books/2011/dec/') self.assertEqual(list(res.context['date_list']), list(sorted(res.context['date_list']))) class WeekArchiveViewTests(TestCase): fixtures = ['generic-views-test-data.json'] Loading