From 3857a08bdb05e30f90f56a7dd0d505ad19f4c403 Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Fri, 13 Mar 2020 06:26:06 -0700 Subject: [PATCH] Fixed #31361 -- Fixed invalid action="" in admin forms. The attribute action="" (empty string) on the
element is invalid HTML5. The spec (https://html.spec.whatwg.org/#attr-fs-action) says: > The action and formaction content attributes, if specified, must have > a value that is a valid non-empty URL potentially surrounded by > spaces. Emphasis on non-empty. The action attribute is allowed to be omitted, in which case the current URL is used which is the same behavior as now. --- .../admin/auth/user/change_password.html | 2 +- .../admin/templates/admin/change_form.html | 2 +- tests/admin_views/tests.py | 32 ++++++++++++------- tests/auth_tests/test_views.py | 3 +- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/django/contrib/admin/templates/admin/auth/user/change_password.html b/django/contrib/admin/templates/admin/auth/user/change_password.html index 2d723cf0d6d..1c3347e6595 100644 --- a/django/contrib/admin/templates/admin/auth/user/change_password.html +++ b/django/contrib/admin/templates/admin/auth/user/change_password.html @@ -19,7 +19,7 @@ {% endblock %} {% endif %} {% block content %}
-{% csrf_token %}{% block form_top %}{% endblock %} +{% csrf_token %}{% block form_top %}{% endblock %}
{% if is_popup %}{% endif %} diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html index f1f317806da..fe19b40e853 100644 --- a/django/contrib/admin/templates/admin/change_form.html +++ b/django/contrib/admin/templates/admin/change_form.html @@ -33,7 +33,7 @@ {% endif %}{% endif %} {% endblock %} -{% csrf_token %}{% block form_top %}{% endblock %} +{% csrf_token %}{% block form_top %}{% endblock %}
{% if is_popup %}{% endif %} {% if to_field %}{% endif %} diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index 833a0cf2c80..d903261052e 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -5868,21 +5868,19 @@ class AdminKeepChangeListFiltersTests(TestCase): self.get_changelist_filters_querystring(), ) - def get_add_url(self): - return '%s?%s' % ( - reverse('admin:auth_user_add', - current_app=self.admin_site.name), - self.get_preserved_filters_querystring(), - ) + def get_add_url(self, add_preserved_filters=True): + url = reverse('admin:auth_user_add', current_app=self.admin_site.name) + if add_preserved_filters: + url = '%s?%s' % (url, self.get_preserved_filters_querystring()) + return url - def get_change_url(self, user_id=None): + def get_change_url(self, user_id=None, add_preserved_filters=True): if user_id is None: user_id = self.get_sample_user_id() - return "%s?%s" % ( - reverse('admin:auth_user_change', args=(user_id,), - current_app=self.admin_site.name), - self.get_preserved_filters_querystring(), - ) + url = reverse('admin:auth_user_change', args=(user_id,), current_app=self.admin_site.name) + if add_preserved_filters: + url = '%s?%s' % (url, self.get_preserved_filters_querystring()) + return url def get_history_url(self, user_id=None): if user_id is None: @@ -5965,6 +5963,11 @@ class AdminKeepChangeListFiltersTests(TestCase): self.assertRedirects(response, self.get_add_url()) post_data.pop('_addanother') + def test_change_view_without_preserved_filters(self): + response = self.client.get(self.get_change_url(add_preserved_filters=False)) + # The action attribute is omitted. + self.assertContains(response, '') + def test_add_view(self): # Get the `add_view`. response = self.client.get(self.get_add_url()) @@ -6003,6 +6006,11 @@ class AdminKeepChangeListFiltersTests(TestCase): self.assertRedirects(response, self.get_add_url()) post_data.pop('_addanother') + def test_add_view_without_preserved_filters(self): + response = self.client.get(self.get_add_url(add_preserved_filters=False)) + # The action attribute is omitted. + self.assertContains(response, '') + def test_delete_view(self): # Test redirect on "Delete". response = self.client.post(self.get_delete_url(), {'post': 'yes'}) diff --git a/tests/auth_tests/test_views.py b/tests/auth_tests/test_views.py index a5f36bb9ea1..f33cbc8382a 100644 --- a/tests/auth_tests/test_views.py +++ b/tests/auth_tests/test_views.py @@ -1284,7 +1284,8 @@ class UUIDUserTests(TestCase): password_change_url = reverse('custom_user_admin:auth_user_password_change', args=(u.pk,)) response = self.client.get(password_change_url) - self.assertEqual(response.status_code, 200) + # The action attribute is omitted. + self.assertContains(response, '') # A LogEntry is created with pk=1 which breaks a FK constraint on MySQL with connection.constraint_checks_disabled():