diff --git a/django/views/generic/dates.py b/django/views/generic/dates.py index 2ec8aabf6a..3b55014e73 100644 --- a/django/views/generic/dates.py +++ b/django/views/generic/dates.py @@ -55,7 +55,10 @@ class YearMixin: The interval is defined by start date <= item date < next start date. """ - return date.replace(year=date.year + 1, month=1, day=1) + try: + return date.replace(year=date.year + 1, month=1, day=1) + except ValueError: + raise Http404(_("Date out of range")) def _get_current_year(self, date): """Return the start date of the current interval.""" @@ -102,7 +105,10 @@ class MonthMixin: The interval is defined by start date <= item date < next start date. """ if date.month == 12: - return date.replace(year=date.year + 1, month=1, day=1) + try: + return date.replace(year=date.year + 1, month=1, day=1) + except ValueError: + raise Http404(_("Date out of range")) else: return date.replace(month=date.month + 1, day=1) @@ -196,7 +202,10 @@ class WeekMixin: The interval is defined by start date <= item date < next start date. """ - return date + datetime.timedelta(days=7 - self._get_weekday(date)) + try: + return date + datetime.timedelta(days=7 - self._get_weekday(date)) + except OverflowError: + raise Http404(_("Date out of range")) def _get_current_week(self, date): """Return the start date of the current interval.""" diff --git a/docs/releases/1.11.2.txt b/docs/releases/1.11.2.txt index 99e82f75a0..ab7d04959f 100644 --- a/docs/releases/1.11.2.txt +++ b/docs/releases/1.11.2.txt @@ -44,3 +44,6 @@ Bugfixes invalid SQL (:ticket:`28199`). * Corrected detection of GDAL 2.1 on Windows (:ticket:`28181`). + +* Made date-based generic views return a 404 rather than crash when given an + out of range date (:ticket:`28209`). diff --git a/tests/generic_views/test_dates.py b/tests/generic_views/test_dates.py index bf462b44fb..454b9e5a1d 100644 --- a/tests/generic_views/test_dates.py +++ b/tests/generic_views/test_dates.py @@ -661,6 +661,18 @@ class DateDetailViewTests(TestDataMixin, TestCase): self.assertEqual(res.context['book'], b) self.assertTemplateUsed(res, 'generic_views/book_detail.html') + def test_year_out_of_range(self): + urls = [ + '/dates/books/9999/', + '/dates/books/9999/12/', + '/dates/books/9999/week/52/', + ] + for url in urls: + with self.subTest(url=url): + res = self.client.get(url) + self.assertEqual(res.status_code, 404) + self.assertEqual(res.context['exception'], 'Date out of range') + def test_invalid_url(self): with self.assertRaises(AttributeError): self.client.get("/dates/books/2008/oct/01/nopk/")