Browse Source

Fixed #31620 -- Added support for %V format to WeekMixin/WeekArchiveView.

Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Hasan Ramezani 4 years ago
parent
commit
8984cab8a8

+ 11 - 6
django/views/generic/dates.py

@@ -218,7 +218,7 @@ class WeekMixin:
         The first day according to the week format is 0 and the last day is 6.
         """
         week_format = self.get_week_format()
-        if week_format == '%W':                 # week starts on Monday
+        if week_format in {'%W', '%V'}:         # week starts on Monday
             return date.weekday()
         elif week_format == '%U':               # week starts on Sunday
             return (date.weekday() + 1) % 7
@@ -485,7 +485,7 @@ class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView):
 
         date_field = self.get_date_field()
         week_format = self.get_week_format()
-        week_choices = {'%W': '1', '%U': '0'}
+        week_choices = {'%W': '1', '%U': '0', '%V': '1'}
         try:
             week_start = week_choices[week_format]
         except KeyError:
@@ -493,10 +493,15 @@ class BaseWeekArchiveView(YearMixin, WeekMixin, BaseDateListView):
                 week_format,
                 ', '.join(sorted(week_choices)),
             ))
-        date = _date_from_string(year, self.get_year_format(),
-                                 week_start, '%w',
-                                 week, week_format)
-
+        year_format = self.get_year_format()
+        if week_format == '%V' and year_format != '%G':
+            raise ValueError(
+                "ISO week directive '%s' is incompatible with the year "
+                "directive '%s'. Use the ISO year '%%G' instead." % (
+                    week_format, year_format,
+                )
+            )
+        date = _date_from_string(year, year_format, week_start, '%w', week, week_format)
         since = self._make_date_lookup_arg(date)
         until = self._make_date_lookup_arg(self._get_next_week(date))
         lookup_kwargs = {

+ 6 - 0
docs/ref/class-based-views/generic-date-based.txt

@@ -342,6 +342,12 @@ views for displaying drilldown pages for date-based data.
       * ``'%W'``: Similar to ``'%U'``, except it assumes that the week
         begins on Monday. This is not the same as the ISO 8601 week number.
 
+      * ``'%V'``: ISO 8601 week number where the week begins on Monday.
+
+        .. versionadded:: 3.2
+
+            Support for the ``'%V'`` week format was added.
+
     **Example myapp/views.py**::
 
         from django.views.generic.dates import WeekArchiveView

+ 6 - 1
docs/ref/class-based-views/mixins-date-based.txt

@@ -180,7 +180,12 @@ Date-based mixins
 
         The :func:`~time.strftime` format to use when parsing the week. By
         default, this is ``'%U'``, which means the week starts on Sunday. Set
-        it to ``'%W'`` if your week starts on Monday.
+        it to ``'%W'`` or ``'%V'`` (ISO 8601 week) if your week starts on
+        Monday.
+
+        .. versionadded:: 3.2
+
+            Support for the ``'%V'`` week format was added.
 
     .. attribute:: week
 

+ 4 - 1
docs/releases/3.2.txt

@@ -166,7 +166,10 @@ Forms
 Generic Views
 ~~~~~~~~~~~~~
 
-* ...
+* The ``week_format`` attributes of
+  :class:`~django.views.generic.dates.WeekMixin` and
+  :class:`~django.views.generic.dates.WeekArchiveView` now support the
+  ``'%V'`` ISO 8601 week format.
 
 Internationalization
 ~~~~~~~~~~~~~~~~~~~~

+ 20 - 1
tests/generic_views/test_dates.py

@@ -538,10 +538,29 @@ class WeekArchiveViewTests(TestDataMixin, TestCase):
         self.assertEqual(res.status_code, 200)
         self.assertEqual(res.context['week'], datetime.date(2008, 9, 29))
 
+    def test_week_iso_format(self):
+        res = self.client.get('/dates/books/2008/week/40/iso_format/')
+        self.assertEqual(res.status_code, 200)
+        self.assertTemplateUsed(res, 'generic_views/book_archive_week.html')
+        self.assertEqual(
+            list(res.context['book_list']),
+            [Book.objects.get(pubdate=datetime.date(2008, 10, 1))],
+        )
+        self.assertEqual(res.context['week'], datetime.date(2008, 9, 29))
+
     def test_unknown_week_format(self):
-        with self.assertRaisesMessage(ValueError, "Unknown week format '%T'. Choices are: %U, %W"):
+        msg = "Unknown week format '%T'. Choices are: %U, %V, %W"
+        with self.assertRaisesMessage(ValueError, msg):
             self.client.get('/dates/books/2008/week/39/unknown_week_format/')
 
+    def test_incompatible_iso_week_format_view(self):
+        msg = (
+            "ISO week directive '%V' is incompatible with the year directive "
+            "'%Y'. Use the ISO year '%G' instead."
+        )
+        with self.assertRaisesMessage(ValueError, msg):
+            self.client.get('/dates/books/2008/week/40/invalid_iso_week_year_format/')
+
     def test_datetime_week_view(self):
         BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
         res = self.client.get('/dates/booksignings/2008/week/13/')

+ 8 - 0
tests/generic_views/urls.py

@@ -190,6 +190,14 @@ urlpatterns = [
         'dates/books/<int:year>/week/<int:week>/unknown_week_format/',
         views.BookWeekArchive.as_view(week_format='%T'),
     ),
+    path(
+        'dates/books/<int:year>/week/<int:week>/iso_format/',
+        views.BookWeekArchive.as_view(year_format='%G', week_format='%V'),
+    ),
+    path(
+        'dates/books/<int:year>/week/<int:week>/invalid_iso_week_year_format/',
+        views.BookWeekArchive.as_view(week_format='%V'),
+    ),
     path('dates/booksignings/<int:year>/week/<int:week>/', views.BookSigningWeekArchive.as_view()),
 
     # DayArchiveView