diff --git a/django/contrib/flatpages/models.py b/django/contrib/flatpages/models.py index f2d66b1c69..2f2473b842 100644 --- a/django/contrib/flatpages/models.py +++ b/django/contrib/flatpages/models.py @@ -1,6 +1,6 @@ from django.contrib.sites.models import Site from django.db import models -from django.urls import get_script_prefix +from django.urls import NoReverseMatch, get_script_prefix, reverse from django.utils.encoding import iri_to_uri from django.utils.translation import gettext_lazy as _ @@ -36,5 +36,12 @@ class FlatPage(models.Model): return "%s -- %s" % (self.url, self.title) def get_absolute_url(self): + from .views import flatpage + + for url in (self.url.lstrip('/'), self.url): + try: + return reverse(flatpage, kwargs={'url': url}) + except NoReverseMatch: + pass # Handle script prefix manually because we bypass reverse() return iri_to_uri(get_script_prefix().rstrip('/') + self.url) diff --git a/tests/flatpages_tests/absolute_urls.py b/tests/flatpages_tests/absolute_urls.py new file mode 100644 index 0000000000..197aa3d6af --- /dev/null +++ b/tests/flatpages_tests/absolute_urls.py @@ -0,0 +1,6 @@ +from django.contrib.flatpages import views +from django.urls import path + +urlpatterns = [ + path('flatpage/', views.flatpage, {'url': '/hardcoded/'}), +] diff --git a/tests/flatpages_tests/no_slash_urls.py b/tests/flatpages_tests/no_slash_urls.py new file mode 100644 index 0000000000..112e6d1638 --- /dev/null +++ b/tests/flatpages_tests/no_slash_urls.py @@ -0,0 +1,5 @@ +from django.urls import include, path + +urlpatterns = [ + path('flatpage', include('django.contrib.flatpages.urls')), +] diff --git a/tests/flatpages_tests/test_models.py b/tests/flatpages_tests/test_models.py index f6a4eec954..4f59c29f6f 100644 --- a/tests/flatpages_tests/test_models.py +++ b/tests/flatpages_tests/test_models.py @@ -1,5 +1,5 @@ from django.contrib.flatpages.models import FlatPage -from django.test import SimpleTestCase +from django.test import SimpleTestCase, override_settings from django.test.utils import override_script_prefix @@ -17,3 +17,16 @@ class FlatpageModelTests(SimpleTestCase): def test_str(self): self.assertEqual(str(self.page), '/café/ -- Café!') + + @override_settings(ROOT_URLCONF='flatpages_tests.urls') + def test_get_absolute_url_include(self): + self.assertEqual(self.page.get_absolute_url(), '/flatpage_root/caf%C3%A9/') + + @override_settings(ROOT_URLCONF='flatpages_tests.no_slash_urls') + def test_get_absolute_url_include_no_slash(self): + self.assertEqual(self.page.get_absolute_url(), '/flatpagecaf%C3%A9/') + + @override_settings(ROOT_URLCONF='flatpages_tests.absolute_urls') + def test_get_absolute_url_with_hardcoded_url(self): + fp = FlatPage(title='Test', url='/hardcoded/') + self.assertEqual(fp.get_absolute_url(), '/flatpage/') diff --git a/tests/flatpages_tests/test_sitemaps.py b/tests/flatpages_tests/test_sitemaps.py index 62522b343e..857dbb86a8 100644 --- a/tests/flatpages_tests/test_sitemaps.py +++ b/tests/flatpages_tests/test_sitemaps.py @@ -31,5 +31,8 @@ class FlatpagesSitemapTests(TestCase): def test_flatpage_sitemap(self): response = self.client.get('/flatpages/sitemap.xml') - self.assertIn(b'http://example.com/foo/', response.getvalue()) - self.assertNotIn(b'http://example.com/private-foo/', response.getvalue()) + self.assertIn(b'http://example.com/flatpage_root/foo/', response.getvalue()) + self.assertNotIn( + b'http://example.com/flatpage_root/private-foo/', + response.getvalue(), + )