From 5eab4d1924613a5506e517f157054b4852ae7dc2 Mon Sep 17 00:00:00 2001 From: Daniel Ivanov Date: Fri, 4 Nov 2022 16:43:40 +0300 Subject: [PATCH] Fixed #34088 -- Fixed Sitemap.get_latest_lastmod() crash with empty items. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug in 480191244d12fefbf95854b2b117c71ffe44749a. Thanks Michal Čihař for the report. --- django/contrib/sitemaps/__init__.py | 2 +- docs/releases/4.1.4.txt | 5 +++++ tests/sitemaps_tests/test_http.py | 10 ++++++++++ tests/sitemaps_tests/urls/http.py | 19 +++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/django/contrib/sitemaps/__init__.py b/django/contrib/sitemaps/__init__.py index 27756d9d96..3d276b60d4 100644 --- a/django/contrib/sitemaps/__init__.py +++ b/django/contrib/sitemaps/__init__.py @@ -167,7 +167,7 @@ class Sitemap: return None if callable(self.lastmod): try: - return max([self.lastmod(item) for item in self.items()]) + return max([self.lastmod(item) for item in self.items()], default=None) except TypeError: return None else: diff --git a/docs/releases/4.1.4.txt b/docs/releases/4.1.4.txt index 21040ebab6..3079fc55b7 100644 --- a/docs/releases/4.1.4.txt +++ b/docs/releases/4.1.4.txt @@ -11,3 +11,8 @@ Bugfixes * Fixed a regression in Django 4.1 that caused an unnecessary table rebuilt when adding ``ManyToManyField`` on SQLite (:ticket:`34138`). + +* Fixed a bug in Django 4.1 that caused a crash of the sitemap index view with + an empty :meth:`Sitemap.items() ` and + a callable :attr:`~django.contrib.sitemaps.Sitemap.lastmod` + (:ticket:`34088`). diff --git a/tests/sitemaps_tests/test_http.py b/tests/sitemaps_tests/test_http.py index 4a269b8737..8c16f66896 100644 --- a/tests/sitemaps_tests/test_http.py +++ b/tests/sitemaps_tests/test_http.py @@ -507,6 +507,16 @@ class HTTPSitemapTests(SitemapTestsBase): self.assertXMLEqual(index_response.content.decode(), expected_content_index) self.assertXMLEqual(sitemap_response.content.decode(), expected_content_sitemap) + def test_callable_sitemod_no_items(self): + index_response = self.client.get("/callable-lastmod-no-items/index.xml") + self.assertNotIn("Last-Modified", index_response) + expected_content_index = """ + + http://example.com/simple/sitemap-callable-lastmod.xml + + """ + self.assertXMLEqual(index_response.content.decode(), expected_content_index) + # RemovedInDjango50Warning class DeprecatedTests(SitemapTestsBase): diff --git a/tests/sitemaps_tests/urls/http.py b/tests/sitemaps_tests/urls/http.py index 9a468de476..75dd4834c0 100644 --- a/tests/sitemaps_tests/urls/http.py +++ b/tests/sitemaps_tests/urls/http.py @@ -114,6 +114,16 @@ class CallableLastmodFullSitemap(Sitemap): return obj.lastmod +class CallableLastmodNoItemsSitemap(Sitemap): + location = "/location/" + + def items(self): + return [] + + def lastmod(self, obj): + return obj.lastmod + + class GetLatestLastmodNoneSiteMap(Sitemap): changefreq = "never" priority = 0.5 @@ -233,6 +243,10 @@ callable_lastmod_full_sitemap = { "callable-lastmod": CallableLastmodFullSitemap, } +callable_lastmod_no_items_sitemap = { + "callable-lastmod": CallableLastmodNoItemsSitemap, +} + urlpatterns = [ path("simple/index.xml", views.index, {"sitemaps": simple_sitemaps}), path("simple-paged/index.xml", views.index, {"sitemaps": simple_sitemaps_paged}), @@ -417,6 +431,11 @@ urlpatterns = [ views.sitemap, {"sitemaps": callable_lastmod_full_sitemap}, ), + path( + "callable-lastmod-no-items/index.xml", + views.index, + {"sitemaps": callable_lastmod_no_items_sitemap}, + ), path( "generic-lastmod/index.xml", views.index,