1. import datetime
    
  2. from unittest import mock
    
  3. 
    
  4. from django.core.exceptions import ImproperlyConfigured
    
  5. from django.test import TestCase, override_settings, skipUnlessDBFeature
    
  6. from django.test.utils import requires_tz_support
    
  7. 
    
  8. from .models import Artist, Author, Book, BookSigning, Page
    
  9. 
    
  10. 
    
  11. def _make_books(n, base_date):
    
  12.     for i in range(n):
    
  13.         Book.objects.create(
    
  14.             name="Book %d" % i,
    
  15.             slug="book-%d" % i,
    
  16.             pages=100 + i,
    
  17.             pubdate=base_date - datetime.timedelta(days=i),
    
  18.         )
    
  19. 
    
  20. 
    
  21. class TestDataMixin:
    
  22.     @classmethod
    
  23.     def setUpTestData(cls):
    
  24.         cls.artist1 = Artist.objects.create(name="Rene Magritte")
    
  25.         cls.author1 = Author.objects.create(
    
  26.             name="Roberto BolaƱo", slug="roberto-bolano"
    
  27.         )
    
  28.         cls.author2 = Author.objects.create(
    
  29.             name="Scott Rosenberg", slug="scott-rosenberg"
    
  30.         )
    
  31.         cls.book1 = Book.objects.create(
    
  32.             name="2066", slug="2066", pages=800, pubdate=datetime.date(2008, 10, 1)
    
  33.         )
    
  34.         cls.book1.authors.add(cls.author1)
    
  35.         cls.book2 = Book.objects.create(
    
  36.             name="Dreaming in Code",
    
  37.             slug="dreaming-in-code",
    
  38.             pages=300,
    
  39.             pubdate=datetime.date(2006, 5, 1),
    
  40.         )
    
  41.         cls.page1 = Page.objects.create(
    
  42.             content="I was once bitten by a moose.",
    
  43.             template="generic_views/page_template.html",
    
  44.         )
    
  45. 
    
  46. 
    
  47. @override_settings(ROOT_URLCONF="generic_views.urls")
    
  48. class ArchiveIndexViewTests(TestDataMixin, TestCase):
    
  49.     def test_archive_view(self):
    
  50.         res = self.client.get("/dates/books/")
    
  51.         self.assertEqual(res.status_code, 200)
    
  52.         self.assertEqual(
    
  53.             list(res.context["date_list"]),
    
  54.             list(Book.objects.dates("pubdate", "year", "DESC")),
    
  55.         )
    
  56.         self.assertEqual(list(res.context["latest"]), list(Book.objects.all()))
    
  57.         self.assertTemplateUsed(res, "generic_views/book_archive.html")
    
  58. 
    
  59.     def test_archive_view_context_object_name(self):
    
  60.         res = self.client.get("/dates/books/context_object_name/")
    
  61.         self.assertEqual(res.status_code, 200)
    
  62.         self.assertEqual(
    
  63.             list(res.context["date_list"]),
    
  64.             list(Book.objects.dates("pubdate", "year", "DESC")),
    
  65.         )
    
  66.         self.assertEqual(list(res.context["thingies"]), list(Book.objects.all()))
    
  67.         self.assertNotIn("latest", res.context)
    
  68.         self.assertTemplateUsed(res, "generic_views/book_archive.html")
    
  69. 
    
  70.     def test_empty_archive_view(self):
    
  71.         Book.objects.all().delete()
    
  72.         res = self.client.get("/dates/books/")
    
  73.         self.assertEqual(res.status_code, 404)
    
  74. 
    
  75.     def test_allow_empty_archive_view(self):
    
  76.         Book.objects.all().delete()
    
  77.         res = self.client.get("/dates/books/allow_empty/")
    
  78.         self.assertEqual(res.status_code, 200)
    
  79.         self.assertEqual(list(res.context["date_list"]), [])
    
  80.         self.assertTemplateUsed(res, "generic_views/book_archive.html")
    
  81. 
    
  82.     def test_archive_view_template(self):
    
  83.         res = self.client.get("/dates/books/template_name/")
    
  84.         self.assertEqual(res.status_code, 200)
    
  85.         self.assertEqual(
    
  86.             list(res.context["date_list"]),
    
  87.             list(Book.objects.dates("pubdate", "year", "DESC")),
    
  88.         )
    
  89.         self.assertEqual(list(res.context["latest"]), list(Book.objects.all()))
    
  90.         self.assertTemplateUsed(res, "generic_views/list.html")
    
  91. 
    
  92.     def test_archive_view_template_suffix(self):
    
  93.         res = self.client.get("/dates/books/template_name_suffix/")
    
  94.         self.assertEqual(res.status_code, 200)
    
  95.         self.assertEqual(
    
  96.             list(res.context["date_list"]),
    
  97.             list(Book.objects.dates("pubdate", "year", "DESC")),
    
  98.         )
    
  99.         self.assertEqual(list(res.context["latest"]), list(Book.objects.all()))
    
  100.         self.assertTemplateUsed(res, "generic_views/book_detail.html")
    
  101. 
    
  102.     def test_archive_view_invalid(self):
    
  103.         msg = (
    
  104.             "BookArchive is missing a QuerySet. Define BookArchive.model, "
    
  105.             "BookArchive.queryset, or override BookArchive.get_queryset()."
    
  106.         )
    
  107.         with self.assertRaisesMessage(ImproperlyConfigured, msg):
    
  108.             self.client.get("/dates/books/invalid/")
    
  109. 
    
  110.     def test_archive_view_by_month(self):
    
  111.         res = self.client.get("/dates/books/by_month/")
    
  112.         self.assertEqual(res.status_code, 200)
    
  113.         self.assertEqual(
    
  114.             list(res.context["date_list"]),
    
  115.             list(Book.objects.dates("pubdate", "month", "DESC")),
    
  116.         )
    
  117. 
    
  118.     def test_paginated_archive_view(self):
    
  119.         _make_books(20, base_date=datetime.date.today())
    
  120.         res = self.client.get("/dates/books/paginated/")
    
  121.         self.assertEqual(res.status_code, 200)
    
  122.         self.assertEqual(
    
  123.             list(res.context["date_list"]),
    
  124.             list(Book.objects.dates("pubdate", "year", "DESC")),
    
  125.         )
    
  126.         self.assertEqual(list(res.context["latest"]), list(Book.objects.all()[0:10]))
    
  127.         self.assertTemplateUsed(res, "generic_views/book_archive.html")
    
  128. 
    
  129.         res = self.client.get("/dates/books/paginated/?page=2")
    
  130.         self.assertEqual(res.status_code, 200)
    
  131.         self.assertEqual(res.context["page_obj"].number, 2)
    
  132.         self.assertEqual(list(res.context["latest"]), list(Book.objects.all()[10:20]))
    
  133. 
    
  134.     def test_paginated_archive_view_does_not_load_entire_table(self):
    
  135.         # Regression test for #18087
    
  136.         _make_books(20, base_date=datetime.date.today())
    
  137.         # 1 query for years list + 1 query for books
    
  138.         with self.assertNumQueries(2):
    
  139.             self.client.get("/dates/books/")
    
  140.         # same as above + 1 query to test if books exist + 1 query to count them
    
  141.         with self.assertNumQueries(4):
    
  142.             self.client.get("/dates/books/paginated/")
    
  143. 
    
  144.     def test_no_duplicate_query(self):
    
  145.         # Regression test for #18354
    
  146.         with self.assertNumQueries(2):
    
  147.             self.client.get("/dates/books/reverse/")
    
  148. 
    
  149.     def test_datetime_archive_view(self):
    
  150.         BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
    
  151.         res = self.client.get("/dates/booksignings/")
    
  152.         self.assertEqual(res.status_code, 200)
    
  153. 
    
  154.     @requires_tz_support
    
  155.     @skipUnlessDBFeature("has_zoneinfo_database")
    
  156.     @override_settings(USE_TZ=True, TIME_ZONE="Africa/Nairobi")
    
  157.     def test_aware_datetime_archive_view(self):
    
  158.         BookSigning.objects.create(
    
  159.             event_date=datetime.datetime(
    
  160.                 2008, 4, 2, 12, 0, tzinfo=datetime.timezone.utc
    
  161.             )
    
  162.         )
    
  163.         res = self.client.get("/dates/booksignings/")
    
  164.         self.assertEqual(res.status_code, 200)
    
  165. 
    
  166.     def test_date_list_order(self):
    
  167.         """date_list should be sorted descending in index"""
    
  168.         _make_books(5, base_date=datetime.date(2011, 12, 25))
    
  169.         res = self.client.get("/dates/books/")
    
  170.         self.assertEqual(res.status_code, 200)
    
  171.         self.assertEqual(
    
  172.             list(res.context["date_list"]),
    
  173.             list(reversed(sorted(res.context["date_list"]))),
    
  174.         )
    
  175. 
    
  176.     def test_archive_view_custom_sorting(self):
    
  177.         Book.objects.create(
    
  178.             name="Zebras for Dummies", pages=600, pubdate=datetime.date(2007, 5, 1)
    
  179.         )
    
  180.         res = self.client.get("/dates/books/sortedbyname/")
    
  181.         self.assertEqual(res.status_code, 200)
    
  182.         self.assertEqual(
    
  183.             list(res.context["date_list"]),
    
  184.             list(Book.objects.dates("pubdate", "year", "DESC")),
    
  185.         )
    
  186.         self.assertEqual(
    
  187.             list(res.context["latest"]), list(Book.objects.order_by("name").all())
    
  188.         )
    
  189.         self.assertTemplateUsed(res, "generic_views/book_archive.html")
    
  190. 
    
  191.     def test_archive_view_custom_sorting_dec(self):
    
  192.         Book.objects.create(
    
  193.             name="Zebras for Dummies", pages=600, pubdate=datetime.date(2007, 5, 1)
    
  194.         )
    
  195.         res = self.client.get("/dates/books/sortedbynamedec/")
    
  196.         self.assertEqual(res.status_code, 200)
    
  197.         self.assertEqual(
    
  198.             list(res.context["date_list"]),
    
  199.             list(Book.objects.dates("pubdate", "year", "DESC")),
    
  200.         )
    
  201.         self.assertEqual(
    
  202.             list(res.context["latest"]), list(Book.objects.order_by("-name").all())
    
  203.         )
    
  204.         self.assertTemplateUsed(res, "generic_views/book_archive.html")
    
  205. 
    
  206.     def test_archive_view_without_date_field(self):
    
  207.         msg = "BookArchiveWithoutDateField.date_field is required."
    
  208.         with self.assertRaisesMessage(ImproperlyConfigured, msg):
    
  209.             self.client.get("/dates/books/without_date_field/")
    
  210. 
    
  211. 
    
  212. @override_settings(ROOT_URLCONF="generic_views.urls")
    
  213. class YearArchiveViewTests(TestDataMixin, TestCase):
    
  214.     def test_year_view(self):
    
  215.         res = self.client.get("/dates/books/2008/")
    
  216.         self.assertEqual(res.status_code, 200)
    
  217.         self.assertEqual(list(res.context["date_list"]), [datetime.date(2008, 10, 1)])
    
  218.         self.assertEqual(res.context["year"], datetime.date(2008, 1, 1))
    
  219.         self.assertTemplateUsed(res, "generic_views/book_archive_year.html")
    
  220. 
    
  221.         # Since allow_empty=False, next/prev years must be valid (#7164)
    
  222.         self.assertIsNone(res.context["next_year"])
    
  223.         self.assertEqual(res.context["previous_year"], datetime.date(2006, 1, 1))
    
  224. 
    
  225.     def test_year_view_make_object_list(self):
    
  226.         res = self.client.get("/dates/books/2006/make_object_list/")
    
  227.         self.assertEqual(res.status_code, 200)
    
  228.         self.assertEqual(list(res.context["date_list"]), [datetime.date(2006, 5, 1)])
    
  229.         self.assertEqual(
    
  230.             list(res.context["book_list"]),
    
  231.             list(Book.objects.filter(pubdate__year=2006)),
    
  232.         )
    
  233.         self.assertEqual(
    
  234.             list(res.context["object_list"]),
    
  235.             list(Book.objects.filter(pubdate__year=2006)),
    
  236.         )
    
  237.         self.assertTemplateUsed(res, "generic_views/book_archive_year.html")
    
  238. 
    
  239.     def test_year_view_empty(self):
    
  240.         res = self.client.get("/dates/books/1999/")
    
  241.         self.assertEqual(res.status_code, 404)
    
  242.         res = self.client.get("/dates/books/1999/allow_empty/")
    
  243.         self.assertEqual(res.status_code, 200)
    
  244.         self.assertEqual(list(res.context["date_list"]), [])
    
  245.         self.assertEqual(list(res.context["book_list"]), [])
    
  246. 
    
  247.         # Since allow_empty=True, next/prev are allowed to be empty years (#7164)
    
  248.         self.assertEqual(res.context["next_year"], datetime.date(2000, 1, 1))
    
  249.         self.assertEqual(res.context["previous_year"], datetime.date(1998, 1, 1))
    
  250. 
    
  251.     def test_year_view_allow_future(self):
    
  252.         # Create a new book in the future
    
  253.         year = datetime.date.today().year + 1
    
  254.         Book.objects.create(
    
  255.             name="The New New Testement", pages=600, pubdate=datetime.date(year, 1, 1)
    
  256.         )
    
  257.         res = self.client.get("/dates/books/%s/" % year)
    
  258.         self.assertEqual(res.status_code, 404)
    
  259. 
    
  260.         res = self.client.get("/dates/books/%s/allow_empty/" % year)
    
  261.         self.assertEqual(res.status_code, 200)
    
  262.         self.assertEqual(list(res.context["book_list"]), [])
    
  263. 
    
  264.         res = self.client.get("/dates/books/%s/allow_future/" % year)
    
  265.         self.assertEqual(res.status_code, 200)
    
  266.         self.assertEqual(list(res.context["date_list"]), [datetime.date(year, 1, 1)])
    
  267. 
    
  268.     def test_year_view_paginated(self):
    
  269.         res = self.client.get("/dates/books/2006/paginated/")
    
  270.         self.assertEqual(res.status_code, 200)
    
  271.         self.assertEqual(
    
  272.             list(res.context["book_list"]),
    
  273.             list(Book.objects.filter(pubdate__year=2006)),
    
  274.         )
    
  275.         self.assertEqual(
    
  276.             list(res.context["object_list"]),
    
  277.             list(Book.objects.filter(pubdate__year=2006)),
    
  278.         )
    
  279.         self.assertTemplateUsed(res, "generic_views/book_archive_year.html")
    
  280. 
    
  281.     def test_year_view_custom_sort_order(self):
    
  282.         # Zebras comes after Dreaming by name, but before on '-pubdate' which
    
  283.         # is the default sorting.
    
  284.         Book.objects.create(
    
  285.             name="Zebras for Dummies", pages=600, pubdate=datetime.date(2006, 9, 1)
    
  286.         )
    
  287.         res = self.client.get("/dates/books/2006/sortedbyname/")
    
  288.         self.assertEqual(res.status_code, 200)
    
  289.         self.assertEqual(
    
  290.             list(res.context["date_list"]),
    
  291.             [datetime.date(2006, 5, 1), datetime.date(2006, 9, 1)],
    
  292.         )
    
  293.         self.assertEqual(
    
  294.             list(res.context["book_list"]),
    
  295.             list(Book.objects.filter(pubdate__year=2006).order_by("name")),
    
  296.         )
    
  297.         self.assertEqual(
    
  298.             list(res.context["object_list"]),
    
  299.             list(Book.objects.filter(pubdate__year=2006).order_by("name")),
    
  300.         )
    
  301.         self.assertTemplateUsed(res, "generic_views/book_archive_year.html")
    
  302. 
    
  303.     def test_year_view_two_custom_sort_orders(self):
    
  304.         Book.objects.create(
    
  305.             name="Zebras for Dummies", pages=300, pubdate=datetime.date(2006, 9, 1)
    
  306.         )
    
  307.         Book.objects.create(
    
  308.             name="Hunting Hippos", pages=400, pubdate=datetime.date(2006, 3, 1)
    
  309.         )
    
  310.         res = self.client.get("/dates/books/2006/sortedbypageandnamedec/")
    
  311.         self.assertEqual(res.status_code, 200)
    
  312.         self.assertEqual(
    
  313.             list(res.context["date_list"]),
    
  314.             [
    
  315.                 datetime.date(2006, 3, 1),
    
  316.                 datetime.date(2006, 5, 1),
    
  317.                 datetime.date(2006, 9, 1),
    
  318.             ],
    
  319.         )
    
  320.         self.assertEqual(
    
  321.             list(res.context["book_list"]),
    
  322.             list(Book.objects.filter(pubdate__year=2006).order_by("pages", "-name")),
    
  323.         )
    
  324.         self.assertEqual(
    
  325.             list(res.context["object_list"]),
    
  326.             list(Book.objects.filter(pubdate__year=2006).order_by("pages", "-name")),
    
  327.         )
    
  328.         self.assertTemplateUsed(res, "generic_views/book_archive_year.html")
    
  329. 
    
  330.     def test_year_view_invalid_pattern(self):
    
  331.         res = self.client.get("/dates/books/no_year/")
    
  332.         self.assertEqual(res.status_code, 404)
    
  333. 
    
  334.     def test_no_duplicate_query(self):
    
  335.         # Regression test for #18354
    
  336.         with self.assertNumQueries(4):
    
  337.             self.client.get("/dates/books/2008/reverse/")
    
  338. 
    
  339.     def test_datetime_year_view(self):
    
  340.         BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
    
  341.         res = self.client.get("/dates/booksignings/2008/")
    
  342.         self.assertEqual(res.status_code, 200)
    
  343. 
    
  344.     @skipUnlessDBFeature("has_zoneinfo_database")
    
  345.     @override_settings(USE_TZ=True, TIME_ZONE="Africa/Nairobi")
    
  346.     def test_aware_datetime_year_view(self):
    
  347.         BookSigning.objects.create(
    
  348.             event_date=datetime.datetime(
    
  349.                 2008, 4, 2, 12, 0, tzinfo=datetime.timezone.utc
    
  350.             )
    
  351.         )
    
  352.         res = self.client.get("/dates/booksignings/2008/")
    
  353.         self.assertEqual(res.status_code, 200)
    
  354. 
    
  355.     def test_date_list_order(self):
    
  356.         """date_list should be sorted ascending in year view"""
    
  357.         _make_books(10, base_date=datetime.date(2011, 12, 25))
    
  358.         res = self.client.get("/dates/books/2011/")
    
  359.         self.assertEqual(
    
  360.             list(res.context["date_list"]), list(sorted(res.context["date_list"]))
    
  361.         )
    
  362. 
    
  363.     @mock.patch("django.views.generic.list.MultipleObjectMixin.get_context_data")
    
  364.     def test_get_context_data_receives_extra_context(self, mock):
    
  365.         """
    
  366.         MultipleObjectMixin.get_context_data() receives the context set by
    
  367.         BaseYearArchiveView.get_dated_items(). This behavior is implemented in
    
  368.         BaseDateListView.get().
    
  369.         """
    
  370.         BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
    
  371.         with self.assertRaisesMessage(
    
  372.             TypeError, "context must be a dict rather than MagicMock."
    
  373.         ):
    
  374.             self.client.get("/dates/booksignings/2008/")
    
  375.         args, kwargs = mock.call_args
    
  376.         # These are context values from get_dated_items().
    
  377.         self.assertEqual(kwargs["year"], datetime.date(2008, 1, 1))
    
  378.         self.assertIsNone(kwargs["previous_year"])
    
  379.         self.assertIsNone(kwargs["next_year"])
    
  380. 
    
  381.     def test_get_dated_items_not_implemented(self):
    
  382.         msg = "A DateView must provide an implementation of get_dated_items()"
    
  383.         with self.assertRaisesMessage(NotImplementedError, msg):
    
  384.             self.client.get("/BaseDateListViewTest/")
    
  385. 
    
  386. 
    
  387. @override_settings(ROOT_URLCONF="generic_views.urls")
    
  388. class MonthArchiveViewTests(TestDataMixin, TestCase):
    
  389.     def test_month_view(self):
    
  390.         res = self.client.get("/dates/books/2008/oct/")
    
  391.         self.assertEqual(res.status_code, 200)
    
  392.         self.assertTemplateUsed(res, "generic_views/book_archive_month.html")
    
  393.         self.assertEqual(list(res.context["date_list"]), [datetime.date(2008, 10, 1)])
    
  394.         self.assertEqual(
    
  395.             list(res.context["book_list"]),
    
  396.             list(Book.objects.filter(pubdate=datetime.date(2008, 10, 1))),
    
  397.         )
    
  398.         self.assertEqual(res.context["month"], datetime.date(2008, 10, 1))
    
  399. 
    
  400.         # Since allow_empty=False, next/prev months must be valid (#7164)
    
  401.         self.assertIsNone(res.context["next_month"])
    
  402.         self.assertEqual(res.context["previous_month"], datetime.date(2006, 5, 1))
    
  403. 
    
  404.     def test_month_view_allow_empty(self):
    
  405.         # allow_empty = False, empty month
    
  406.         res = self.client.get("/dates/books/2000/jan/")
    
  407.         self.assertEqual(res.status_code, 404)
    
  408. 
    
  409.         # allow_empty = True, empty month
    
  410.         res = self.client.get("/dates/books/2000/jan/allow_empty/")
    
  411.         self.assertEqual(res.status_code, 200)
    
  412.         self.assertEqual(list(res.context["date_list"]), [])
    
  413.         self.assertEqual(list(res.context["book_list"]), [])
    
  414.         self.assertEqual(res.context["month"], datetime.date(2000, 1, 1))
    
  415. 
    
  416.         # Since allow_empty=True, next/prev are allowed to be empty months (#7164)
    
  417.         self.assertEqual(res.context["next_month"], datetime.date(2000, 2, 1))
    
  418.         self.assertEqual(res.context["previous_month"], datetime.date(1999, 12, 1))
    
  419. 
    
  420.         # allow_empty but not allow_future: next_month should be empty (#7164)
    
  421.         url = datetime.date.today().strftime("/dates/books/%Y/%b/allow_empty/").lower()
    
  422.         res = self.client.get(url)
    
  423.         self.assertEqual(res.status_code, 200)
    
  424.         self.assertIsNone(res.context["next_month"])
    
  425. 
    
  426.     def test_month_view_allow_future(self):
    
  427.         future = (datetime.date.today() + datetime.timedelta(days=60)).replace(day=1)
    
  428.         urlbit = future.strftime("%Y/%b").lower()
    
  429.         b = Book.objects.create(name="The New New Testement", pages=600, pubdate=future)
    
  430. 
    
  431.         # allow_future = False, future month
    
  432.         res = self.client.get("/dates/books/%s/" % urlbit)
    
  433.         self.assertEqual(res.status_code, 404)
    
  434. 
    
  435.         # allow_future = True, valid future month
    
  436.         res = self.client.get("/dates/books/%s/allow_future/" % urlbit)
    
  437.         self.assertEqual(res.status_code, 200)
    
  438.         self.assertEqual(res.context["date_list"][0], b.pubdate)
    
  439.         self.assertEqual(list(res.context["book_list"]), [b])
    
  440.         self.assertEqual(res.context["month"], future)
    
  441. 
    
  442.         # Since allow_future = True but not allow_empty, next/prev are not
    
  443.         # allowed to be empty months (#7164)
    
  444.         self.assertIsNone(res.context["next_month"])
    
  445.         self.assertEqual(res.context["previous_month"], datetime.date(2008, 10, 1))
    
  446. 
    
  447.         # allow_future, but not allow_empty, with a current month. So next
    
  448.         # should be in the future (yup, #7164, again)
    
  449.         res = self.client.get("/dates/books/2008/oct/allow_future/")
    
  450.         self.assertEqual(res.status_code, 200)
    
  451.         self.assertEqual(res.context["next_month"], future)
    
  452.         self.assertEqual(res.context["previous_month"], datetime.date(2006, 5, 1))
    
  453. 
    
  454.     def test_month_view_paginated(self):
    
  455.         res = self.client.get("/dates/books/2008/oct/paginated/")
    
  456.         self.assertEqual(res.status_code, 200)
    
  457.         self.assertEqual(
    
  458.             list(res.context["book_list"]),
    
  459.             list(Book.objects.filter(pubdate__year=2008, pubdate__month=10)),
    
  460.         )
    
  461.         self.assertEqual(
    
  462.             list(res.context["object_list"]),
    
  463.             list(Book.objects.filter(pubdate__year=2008, pubdate__month=10)),
    
  464.         )
    
  465.         self.assertTemplateUsed(res, "generic_views/book_archive_month.html")
    
  466. 
    
  467.     def test_custom_month_format(self):
    
  468.         res = self.client.get("/dates/books/2008/10/")
    
  469.         self.assertEqual(res.status_code, 200)
    
  470. 
    
  471.     def test_month_view_invalid_pattern(self):
    
  472.         res = self.client.get("/dates/books/2007/no_month/")
    
  473.         self.assertEqual(res.status_code, 404)
    
  474. 
    
  475.     def test_previous_month_without_content(self):
    
  476.         "Content can exist on any day of the previous month. Refs #14711"
    
  477.         self.pubdate_list = [
    
  478.             datetime.date(2010, month, day) for month, day in ((9, 1), (10, 2), (11, 3))
    
  479.         ]
    
  480.         for pubdate in self.pubdate_list:
    
  481.             name = str(pubdate)
    
  482.             Book.objects.create(name=name, slug=name, pages=100, pubdate=pubdate)
    
  483. 
    
  484.         res = self.client.get("/dates/books/2010/nov/allow_empty/")
    
  485.         self.assertEqual(res.status_code, 200)
    
  486.         self.assertEqual(res.context["previous_month"], datetime.date(2010, 10, 1))
    
  487.         # The following test demonstrates the bug
    
  488.         res = self.client.get("/dates/books/2010/nov/")
    
  489.         self.assertEqual(res.status_code, 200)
    
  490.         self.assertEqual(res.context["previous_month"], datetime.date(2010, 10, 1))
    
  491.         # The bug does not occur here because a Book with pubdate of Sep 1 exists
    
  492.         res = self.client.get("/dates/books/2010/oct/")
    
  493.         self.assertEqual(res.status_code, 200)
    
  494.         self.assertEqual(res.context["previous_month"], datetime.date(2010, 9, 1))
    
  495. 
    
  496.     def test_datetime_month_view(self):
    
  497.         BookSigning.objects.create(event_date=datetime.datetime(2008, 2, 1, 12, 0))
    
  498.         BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
    
  499.         BookSigning.objects.create(event_date=datetime.datetime(2008, 6, 3, 12, 0))
    
  500.         res = self.client.get("/dates/booksignings/2008/apr/")
    
  501.         self.assertEqual(res.status_code, 200)
    
  502. 
    
  503.     def test_month_view_get_month_from_request(self):
    
  504.         oct1 = datetime.date(2008, 10, 1)
    
  505.         res = self.client.get("/dates/books/without_month/2008/?month=oct")
    
  506.         self.assertEqual(res.status_code, 200)
    
  507.         self.assertTemplateUsed(res, "generic_views/book_archive_month.html")
    
  508.         self.assertEqual(list(res.context["date_list"]), [oct1])
    
  509.         self.assertEqual(
    
  510.             list(res.context["book_list"]), list(Book.objects.filter(pubdate=oct1))
    
  511.         )
    
  512.         self.assertEqual(res.context["month"], oct1)
    
  513. 
    
  514.     def test_month_view_without_month_in_url(self):
    
  515.         res = self.client.get("/dates/books/without_month/2008/")
    
  516.         self.assertEqual(res.status_code, 404)
    
  517.         self.assertEqual(res.context["exception"], "No month specified")
    
  518. 
    
  519.     @skipUnlessDBFeature("has_zoneinfo_database")
    
  520.     @override_settings(USE_TZ=True, TIME_ZONE="Africa/Nairobi")
    
  521.     def test_aware_datetime_month_view(self):
    
  522.         BookSigning.objects.create(
    
  523.             event_date=datetime.datetime(
    
  524.                 2008, 2, 1, 12, 0, tzinfo=datetime.timezone.utc
    
  525.             )
    
  526.         )
    
  527.         BookSigning.objects.create(
    
  528.             event_date=datetime.datetime(
    
  529.                 2008, 4, 2, 12, 0, tzinfo=datetime.timezone.utc
    
  530.             )
    
  531.         )
    
  532.         BookSigning.objects.create(
    
  533.             event_date=datetime.datetime(
    
  534.                 2008, 6, 3, 12, 0, tzinfo=datetime.timezone.utc
    
  535.             )
    
  536.         )
    
  537.         res = self.client.get("/dates/booksignings/2008/apr/")
    
  538.         self.assertEqual(res.status_code, 200)
    
  539. 
    
  540.     def test_date_list_order(self):
    
  541.         """date_list should be sorted ascending in month view"""
    
  542.         _make_books(10, base_date=datetime.date(2011, 12, 25))
    
  543.         res = self.client.get("/dates/books/2011/dec/")
    
  544.         self.assertEqual(
    
  545.             list(res.context["date_list"]), list(sorted(res.context["date_list"]))
    
  546.         )
    
  547. 
    
  548. 
    
  549. @override_settings(ROOT_URLCONF="generic_views.urls")
    
  550. class WeekArchiveViewTests(TestDataMixin, TestCase):
    
  551.     def test_week_view(self):
    
  552.         res = self.client.get("/dates/books/2008/week/39/")
    
  553.         self.assertEqual(res.status_code, 200)
    
  554.         self.assertTemplateUsed(res, "generic_views/book_archive_week.html")
    
  555.         self.assertEqual(
    
  556.             res.context["book_list"][0],
    
  557.             Book.objects.get(pubdate=datetime.date(2008, 10, 1)),
    
  558.         )
    
  559.         self.assertEqual(res.context["week"], datetime.date(2008, 9, 28))
    
  560. 
    
  561.         # Since allow_empty=False, next/prev weeks must be valid
    
  562.         self.assertIsNone(res.context["next_week"])
    
  563.         self.assertEqual(res.context["previous_week"], datetime.date(2006, 4, 30))
    
  564. 
    
  565.     def test_week_view_allow_empty(self):
    
  566.         # allow_empty = False, empty week
    
  567.         res = self.client.get("/dates/books/2008/week/12/")
    
  568.         self.assertEqual(res.status_code, 404)
    
  569. 
    
  570.         # allow_empty = True, empty month
    
  571.         res = self.client.get("/dates/books/2008/week/12/allow_empty/")
    
  572.         self.assertEqual(res.status_code, 200)
    
  573.         self.assertEqual(list(res.context["book_list"]), [])
    
  574.         self.assertEqual(res.context["week"], datetime.date(2008, 3, 23))
    
  575. 
    
  576.         # Since allow_empty=True, next/prev are allowed to be empty weeks
    
  577.         self.assertEqual(res.context["next_week"], datetime.date(2008, 3, 30))
    
  578.         self.assertEqual(res.context["previous_week"], datetime.date(2008, 3, 16))
    
  579. 
    
  580.         # allow_empty but not allow_future: next_week should be empty
    
  581.         url = (
    
  582.             datetime.date.today()
    
  583.             .strftime("/dates/books/%Y/week/%U/allow_empty/")
    
  584.             .lower()
    
  585.         )
    
  586.         res = self.client.get(url)
    
  587.         self.assertEqual(res.status_code, 200)
    
  588.         self.assertIsNone(res.context["next_week"])
    
  589. 
    
  590.     def test_week_view_allow_future(self):
    
  591.         # January 7th always falls in week 1, given Python's definition of week numbers
    
  592.         future = datetime.date(datetime.date.today().year + 1, 1, 7)
    
  593.         future_sunday = future - datetime.timedelta(days=(future.weekday() + 1) % 7)
    
  594.         b = Book.objects.create(name="The New New Testement", pages=600, pubdate=future)
    
  595. 
    
  596.         res = self.client.get("/dates/books/%s/week/1/" % future.year)
    
  597.         self.assertEqual(res.status_code, 404)
    
  598. 
    
  599.         res = self.client.get("/dates/books/%s/week/1/allow_future/" % future.year)
    
  600.         self.assertEqual(res.status_code, 200)
    
  601.         self.assertEqual(list(res.context["book_list"]), [b])
    
  602.         self.assertEqual(res.context["week"], future_sunday)
    
  603. 
    
  604.         # Since allow_future = True but not allow_empty, next/prev are not
    
  605.         # allowed to be empty weeks
    
  606.         self.assertIsNone(res.context["next_week"])
    
  607.         self.assertEqual(res.context["previous_week"], datetime.date(2008, 9, 28))
    
  608. 
    
  609.         # allow_future, but not allow_empty, with a current week. So next
    
  610.         # should be in the future
    
  611.         res = self.client.get("/dates/books/2008/week/39/allow_future/")
    
  612.         self.assertEqual(res.status_code, 200)
    
  613.         self.assertEqual(res.context["next_week"], future_sunday)
    
  614.         self.assertEqual(res.context["previous_week"], datetime.date(2006, 4, 30))
    
  615. 
    
  616.     def test_week_view_paginated(self):
    
  617.         week_start = datetime.date(2008, 9, 28)
    
  618.         week_end = week_start + datetime.timedelta(days=7)
    
  619.         res = self.client.get("/dates/books/2008/week/39/")
    
  620.         self.assertEqual(res.status_code, 200)
    
  621.         self.assertEqual(
    
  622.             list(res.context["book_list"]),
    
  623.             list(Book.objects.filter(pubdate__gte=week_start, pubdate__lt=week_end)),
    
  624.         )
    
  625.         self.assertEqual(
    
  626.             list(res.context["object_list"]),
    
  627.             list(Book.objects.filter(pubdate__gte=week_start, pubdate__lt=week_end)),
    
  628.         )
    
  629.         self.assertTemplateUsed(res, "generic_views/book_archive_week.html")
    
  630. 
    
  631.     def test_week_view_invalid_pattern(self):
    
  632.         res = self.client.get("/dates/books/2007/week/no_week/")
    
  633.         self.assertEqual(res.status_code, 404)
    
  634. 
    
  635.     def test_week_start_Monday(self):
    
  636.         # Regression for #14752
    
  637.         res = self.client.get("/dates/books/2008/week/39/")
    
  638.         self.assertEqual(res.status_code, 200)
    
  639.         self.assertEqual(res.context["week"], datetime.date(2008, 9, 28))
    
  640. 
    
  641.         res = self.client.get("/dates/books/2008/week/39/monday/")
    
  642.         self.assertEqual(res.status_code, 200)
    
  643.         self.assertEqual(res.context["week"], datetime.date(2008, 9, 29))
    
  644. 
    
  645.     def test_week_iso_format(self):
    
  646.         res = self.client.get("/dates/books/2008/week/40/iso_format/")
    
  647.         self.assertEqual(res.status_code, 200)
    
  648.         self.assertTemplateUsed(res, "generic_views/book_archive_week.html")
    
  649.         self.assertEqual(
    
  650.             list(res.context["book_list"]),
    
  651.             [Book.objects.get(pubdate=datetime.date(2008, 10, 1))],
    
  652.         )
    
  653.         self.assertEqual(res.context["week"], datetime.date(2008, 9, 29))
    
  654. 
    
  655.     def test_unknown_week_format(self):
    
  656.         msg = "Unknown week format '%T'. Choices are: %U, %V, %W"
    
  657.         with self.assertRaisesMessage(ValueError, msg):
    
  658.             self.client.get("/dates/books/2008/week/39/unknown_week_format/")
    
  659. 
    
  660.     def test_incompatible_iso_week_format_view(self):
    
  661.         msg = (
    
  662.             "ISO week directive '%V' is incompatible with the year directive "
    
  663.             "'%Y'. Use the ISO year '%G' instead."
    
  664.         )
    
  665.         with self.assertRaisesMessage(ValueError, msg):
    
  666.             self.client.get("/dates/books/2008/week/40/invalid_iso_week_year_format/")
    
  667. 
    
  668.     def test_datetime_week_view(self):
    
  669.         BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
    
  670.         res = self.client.get("/dates/booksignings/2008/week/13/")
    
  671.         self.assertEqual(res.status_code, 200)
    
  672. 
    
  673.     @override_settings(USE_TZ=True, TIME_ZONE="Africa/Nairobi")
    
  674.     def test_aware_datetime_week_view(self):
    
  675.         BookSigning.objects.create(
    
  676.             event_date=datetime.datetime(
    
  677.                 2008, 4, 2, 12, 0, tzinfo=datetime.timezone.utc
    
  678.             )
    
  679.         )
    
  680.         res = self.client.get("/dates/booksignings/2008/week/13/")
    
  681.         self.assertEqual(res.status_code, 200)
    
  682. 
    
  683. 
    
  684. @override_settings(ROOT_URLCONF="generic_views.urls")
    
  685. class DayArchiveViewTests(TestDataMixin, TestCase):
    
  686.     def test_day_view(self):
    
  687.         res = self.client.get("/dates/books/2008/oct/01/")
    
  688.         self.assertEqual(res.status_code, 200)
    
  689.         self.assertTemplateUsed(res, "generic_views/book_archive_day.html")
    
  690.         self.assertEqual(
    
  691.             list(res.context["book_list"]),
    
  692.             list(Book.objects.filter(pubdate=datetime.date(2008, 10, 1))),
    
  693.         )
    
  694.         self.assertEqual(res.context["day"], datetime.date(2008, 10, 1))
    
  695. 
    
  696.         # Since allow_empty=False, next/prev days must be valid.
    
  697.         self.assertIsNone(res.context["next_day"])
    
  698.         self.assertEqual(res.context["previous_day"], datetime.date(2006, 5, 1))
    
  699. 
    
  700.     def test_day_view_allow_empty(self):
    
  701.         # allow_empty = False, empty month
    
  702.         res = self.client.get("/dates/books/2000/jan/1/")
    
  703.         self.assertEqual(res.status_code, 404)
    
  704. 
    
  705.         # allow_empty = True, empty month
    
  706.         res = self.client.get("/dates/books/2000/jan/1/allow_empty/")
    
  707.         self.assertEqual(res.status_code, 200)
    
  708.         self.assertEqual(list(res.context["book_list"]), [])
    
  709.         self.assertEqual(res.context["day"], datetime.date(2000, 1, 1))
    
  710. 
    
  711.         # Since it's allow empty, next/prev are allowed to be empty months (#7164)
    
  712.         self.assertEqual(res.context["next_day"], datetime.date(2000, 1, 2))
    
  713.         self.assertEqual(res.context["previous_day"], datetime.date(1999, 12, 31))
    
  714. 
    
  715.         # allow_empty but not allow_future: next_month should be empty (#7164)
    
  716.         url = (
    
  717.             datetime.date.today().strftime("/dates/books/%Y/%b/%d/allow_empty/").lower()
    
  718.         )
    
  719.         res = self.client.get(url)
    
  720.         self.assertEqual(res.status_code, 200)
    
  721.         self.assertIsNone(res.context["next_day"])
    
  722. 
    
  723.     def test_day_view_allow_future(self):
    
  724.         future = datetime.date.today() + datetime.timedelta(days=60)
    
  725.         urlbit = future.strftime("%Y/%b/%d").lower()
    
  726.         b = Book.objects.create(name="The New New Testement", pages=600, pubdate=future)
    
  727. 
    
  728.         # allow_future = False, future month
    
  729.         res = self.client.get("/dates/books/%s/" % urlbit)
    
  730.         self.assertEqual(res.status_code, 404)
    
  731. 
    
  732.         # allow_future = True, valid future month
    
  733.         res = self.client.get("/dates/books/%s/allow_future/" % urlbit)
    
  734.         self.assertEqual(res.status_code, 200)
    
  735.         self.assertEqual(list(res.context["book_list"]), [b])
    
  736.         self.assertEqual(res.context["day"], future)
    
  737. 
    
  738.         # allow_future but not allow_empty, next/prev must be valid
    
  739.         self.assertIsNone(res.context["next_day"])
    
  740.         self.assertEqual(res.context["previous_day"], datetime.date(2008, 10, 1))
    
  741. 
    
  742.         # allow_future, but not allow_empty, with a current month.
    
  743.         res = self.client.get("/dates/books/2008/oct/01/allow_future/")
    
  744.         self.assertEqual(res.status_code, 200)
    
  745.         self.assertEqual(res.context["next_day"], future)
    
  746.         self.assertEqual(res.context["previous_day"], datetime.date(2006, 5, 1))
    
  747. 
    
  748.         # allow_future for yesterday, next_day is today (#17192)
    
  749.         today = datetime.date.today()
    
  750.         yesterday = today - datetime.timedelta(days=1)
    
  751.         res = self.client.get(
    
  752.             "/dates/books/%s/allow_empty_and_future/"
    
  753.             % yesterday.strftime("%Y/%b/%d").lower()
    
  754.         )
    
  755.         self.assertEqual(res.context["next_day"], today)
    
  756. 
    
  757.     def test_day_view_paginated(self):
    
  758.         res = self.client.get("/dates/books/2008/oct/1/")
    
  759.         self.assertEqual(res.status_code, 200)
    
  760.         self.assertEqual(
    
  761.             list(res.context["book_list"]),
    
  762.             list(
    
  763.                 Book.objects.filter(
    
  764.                     pubdate__year=2008, pubdate__month=10, pubdate__day=1
    
  765.                 )
    
  766.             ),
    
  767.         )
    
  768.         self.assertEqual(
    
  769.             list(res.context["object_list"]),
    
  770.             list(
    
  771.                 Book.objects.filter(
    
  772.                     pubdate__year=2008, pubdate__month=10, pubdate__day=1
    
  773.                 )
    
  774.             ),
    
  775.         )
    
  776.         self.assertTemplateUsed(res, "generic_views/book_archive_day.html")
    
  777. 
    
  778.     def test_next_prev_context(self):
    
  779.         res = self.client.get("/dates/books/2008/oct/01/")
    
  780.         self.assertEqual(
    
  781.             res.content, b"Archive for Oct. 1, 2008. Previous day is May 1, 2006\n"
    
  782.         )
    
  783. 
    
  784.     def test_custom_month_format(self):
    
  785.         res = self.client.get("/dates/books/2008/10/01/")
    
  786.         self.assertEqual(res.status_code, 200)
    
  787. 
    
  788.     def test_day_view_invalid_pattern(self):
    
  789.         res = self.client.get("/dates/books/2007/oct/no_day/")
    
  790.         self.assertEqual(res.status_code, 404)
    
  791. 
    
  792.     def test_today_view(self):
    
  793.         res = self.client.get("/dates/books/today/")
    
  794.         self.assertEqual(res.status_code, 404)
    
  795.         res = self.client.get("/dates/books/today/allow_empty/")
    
  796.         self.assertEqual(res.status_code, 200)
    
  797.         self.assertEqual(res.context["day"], datetime.date.today())
    
  798. 
    
  799.     def test_datetime_day_view(self):
    
  800.         BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
    
  801.         res = self.client.get("/dates/booksignings/2008/apr/2/")
    
  802.         self.assertEqual(res.status_code, 200)
    
  803. 
    
  804.     @requires_tz_support
    
  805.     @override_settings(USE_TZ=True, TIME_ZONE="Africa/Nairobi")
    
  806.     def test_aware_datetime_day_view(self):
    
  807.         bs = BookSigning.objects.create(
    
  808.             event_date=datetime.datetime(
    
  809.                 2008, 4, 2, 12, 0, tzinfo=datetime.timezone.utc
    
  810.             )
    
  811.         )
    
  812.         res = self.client.get("/dates/booksignings/2008/apr/2/")
    
  813.         self.assertEqual(res.status_code, 200)
    
  814.         # 2008-04-02T00:00:00+03:00 (beginning of day) >
    
  815.         # 2008-04-01T22:00:00+00:00 (book signing event date).
    
  816.         bs.event_date = datetime.datetime(
    
  817.             2008, 4, 1, 22, 0, tzinfo=datetime.timezone.utc
    
  818.         )
    
  819.         bs.save()
    
  820.         res = self.client.get("/dates/booksignings/2008/apr/2/")
    
  821.         self.assertEqual(res.status_code, 200)
    
  822.         # 2008-04-03T00:00:00+03:00 (end of day) > 2008-04-02T22:00:00+00:00
    
  823.         # (book signing event date).
    
  824.         bs.event_date = datetime.datetime(
    
  825.             2008, 4, 2, 22, 0, tzinfo=datetime.timezone.utc
    
  826.         )
    
  827.         bs.save()
    
  828.         res = self.client.get("/dates/booksignings/2008/apr/2/")
    
  829.         self.assertEqual(res.status_code, 404)
    
  830. 
    
  831. 
    
  832. @override_settings(ROOT_URLCONF="generic_views.urls")
    
  833. class DateDetailViewTests(TestDataMixin, TestCase):
    
  834.     def test_date_detail_by_pk(self):
    
  835.         res = self.client.get("/dates/books/2008/oct/01/%s/" % self.book1.pk)
    
  836.         self.assertEqual(res.status_code, 200)
    
  837.         self.assertEqual(res.context["object"], self.book1)
    
  838.         self.assertEqual(res.context["book"], self.book1)
    
  839.         self.assertTemplateUsed(res, "generic_views/book_detail.html")
    
  840. 
    
  841.     def test_date_detail_by_slug(self):
    
  842.         res = self.client.get("/dates/books/2006/may/01/byslug/dreaming-in-code/")
    
  843.         self.assertEqual(res.status_code, 200)
    
  844.         self.assertEqual(res.context["book"], Book.objects.get(slug="dreaming-in-code"))
    
  845. 
    
  846.     def test_date_detail_custom_month_format(self):
    
  847.         res = self.client.get("/dates/books/2008/10/01/%s/" % self.book1.pk)
    
  848.         self.assertEqual(res.status_code, 200)
    
  849.         self.assertEqual(res.context["book"], self.book1)
    
  850. 
    
  851.     def test_date_detail_allow_future(self):
    
  852.         future = datetime.date.today() + datetime.timedelta(days=60)
    
  853.         urlbit = future.strftime("%Y/%b/%d").lower()
    
  854.         b = Book.objects.create(
    
  855.             name="The New New Testement", slug="new-new", pages=600, pubdate=future
    
  856.         )
    
  857. 
    
  858.         res = self.client.get("/dates/books/%s/new-new/" % urlbit)
    
  859.         self.assertEqual(res.status_code, 404)
    
  860. 
    
  861.         res = self.client.get("/dates/books/%s/%s/allow_future/" % (urlbit, b.id))
    
  862.         self.assertEqual(res.status_code, 200)
    
  863.         self.assertEqual(res.context["book"], b)
    
  864.         self.assertTemplateUsed(res, "generic_views/book_detail.html")
    
  865. 
    
  866.     def test_year_out_of_range(self):
    
  867.         urls = [
    
  868.             "/dates/books/9999/",
    
  869.             "/dates/books/9999/12/",
    
  870.             "/dates/books/9999/week/52/",
    
  871.         ]
    
  872.         for url in urls:
    
  873.             with self.subTest(url=url):
    
  874.                 res = self.client.get(url)
    
  875.                 self.assertEqual(res.status_code, 404)
    
  876.                 self.assertEqual(res.context["exception"], "Date out of range")
    
  877. 
    
  878.     def test_invalid_url(self):
    
  879.         msg = (
    
  880.             "Generic detail view BookDetail must be called with either an "
    
  881.             "object pk or a slug in the URLconf."
    
  882.         )
    
  883.         with self.assertRaisesMessage(AttributeError, msg):
    
  884.             self.client.get("/dates/books/2008/oct/01/nopk/")
    
  885. 
    
  886.     def test_get_object_custom_queryset(self):
    
  887.         """
    
  888.         Custom querysets are used when provided to
    
  889.         BaseDateDetailView.get_object().
    
  890.         """
    
  891.         res = self.client.get(
    
  892.             "/dates/books/get_object_custom_queryset/2006/may/01/%s/" % self.book2.pk
    
  893.         )
    
  894.         self.assertEqual(res.status_code, 200)
    
  895.         self.assertEqual(res.context["object"], self.book2)
    
  896.         self.assertEqual(res.context["book"], self.book2)
    
  897.         self.assertTemplateUsed(res, "generic_views/book_detail.html")
    
  898. 
    
  899.         res = self.client.get(
    
  900.             "/dates/books/get_object_custom_queryset/2008/oct/01/9999999/"
    
  901.         )
    
  902.         self.assertEqual(res.status_code, 404)
    
  903. 
    
  904.     def test_get_object_custom_queryset_numqueries(self):
    
  905.         with self.assertNumQueries(1):
    
  906.             self.client.get("/dates/books/get_object_custom_queryset/2006/may/01/2/")
    
  907. 
    
  908.     def test_datetime_date_detail(self):
    
  909.         bs = BookSigning.objects.create(event_date=datetime.datetime(2008, 4, 2, 12, 0))
    
  910.         res = self.client.get("/dates/booksignings/2008/apr/2/%d/" % bs.pk)
    
  911.         self.assertEqual(res.status_code, 200)
    
  912. 
    
  913.     @requires_tz_support
    
  914.     @override_settings(USE_TZ=True, TIME_ZONE="Africa/Nairobi")
    
  915.     def test_aware_datetime_date_detail(self):
    
  916.         bs = BookSigning.objects.create(
    
  917.             event_date=datetime.datetime(
    
  918.                 2008, 4, 2, 12, 0, tzinfo=datetime.timezone.utc
    
  919.             )
    
  920.         )
    
  921.         res = self.client.get("/dates/booksignings/2008/apr/2/%d/" % bs.pk)
    
  922.         self.assertEqual(res.status_code, 200)
    
  923.         # 2008-04-02T00:00:00+03:00 (beginning of day) >
    
  924.         # 2008-04-01T22:00:00+00:00 (book signing event date).
    
  925.         bs.event_date = datetime.datetime(
    
  926.             2008, 4, 1, 22, 0, tzinfo=datetime.timezone.utc
    
  927.         )
    
  928.         bs.save()
    
  929.         res = self.client.get("/dates/booksignings/2008/apr/2/%d/" % bs.pk)
    
  930.         self.assertEqual(res.status_code, 200)
    
  931.         # 2008-04-03T00:00:00+03:00 (end of day) > 2008-04-02T22:00:00+00:00
    
  932.         # (book signing event date).
    
  933.         bs.event_date = datetime.datetime(
    
  934.             2008, 4, 2, 22, 0, tzinfo=datetime.timezone.utc
    
  935.         )
    
  936.         bs.save()
    
  937.         res = self.client.get("/dates/booksignings/2008/apr/2/%d/" % bs.pk)
    
  938.         self.assertEqual(res.status_code, 404)