diff --git a/django/contrib/admin/static/admin/css/base.css b/django/contrib/admin/static/admin/css/base.css index 37910431a0..4f4773284e 100644 --- a/django/contrib/admin/static/admin/css/base.css +++ b/django/contrib/admin/static/admin/css/base.css @@ -773,7 +773,6 @@ a.deletelink:focus, a.deletelink:hover { padding-left: 0; float: right; position: relative; - margin-top: -48px; } .object-tools li { @@ -821,6 +820,10 @@ a.deletelink:focus, a.deletelink:hover { background-image: url(../img/tooltag-add.svg); } +.object-tools:has(a.addlink) { + margin-top: -48px; +} + /* OBJECT HISTORY */ #change-history table { diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html index 236d759483..92f7210e02 100644 --- a/django/contrib/admin/templates/admin/base.html +++ b/django/contrib/admin/templates/admin/base.html @@ -98,9 +98,9 @@
{% block pretitle %}{% endblock %} {% block content_title %}{% if title %}

{{ title }}

{% endif %}{% endblock %} + {% block object-tools %}{% endblock %} {% block content_subtitle %}{% if subtitle %}

{{ subtitle }}

{% endif %}{% endblock %} {% block content %} - {% block object-tools %}{% endblock %} {{ content }} {% endblock %} {% block sidebar %}{% endblock %} diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html index 8e7ced9a48..11536b0965 100644 --- a/django/contrib/admin/templates/admin/change_form.html +++ b/django/contrib/admin/templates/admin/change_form.html @@ -24,7 +24,6 @@ {% endblock %} {% endif %} -{% block content %}
{% block object-tools %} {% if change and not is_popup %} {% endif %} {% endblock %} + +{% block content %}
{% csrf_token %}{% block form_top %}{% endblock %}
{% if is_popup %}{% endif %} diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html index b0b4c31619..cf96df9fe2 100644 --- a/django/contrib/admin/templates/admin/change_list.html +++ b/django/contrib/admin/templates/admin/change_list.html @@ -39,15 +39,16 @@ {% block coltype %}{% endblock %} +{% block object-tools %} +
    + {% block object-tools-items %} + {% change_list_object_tools %} + {% endblock %} +
+{% endblock %} + {% block content %}
- {% block object-tools %} -
    - {% block object-tools-items %} - {% change_list_object_tools %} - {% endblock %} -
- {% endblock %} {% if cl.formset and cl.formset.errors %}

{% blocktranslate count counter=cl.formset.total_error_count %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktranslate %} diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index 8e2c55804b..2b14238f21 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -127,6 +127,7 @@ from .models import ( Song, State, Story, + Subscriber, SuperSecretHideout, SuperVillain, Telegram, @@ -6861,6 +6862,24 @@ class SeleniumTests(AdminSeleniumTestCase): name_input_value = name_input.get_attribute("value") self.assertEqual(name_input_value, "Test section 1") + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) + def test_long_object_str_on_change_view(self): + from selenium.webdriver.common.by import By + + self.admin_login( + username="super", password="secret", login_url=reverse("admin:index") + ) + s = Subscriber.objects.create(name="a " * 40, email="b " * 80) + self.selenium.get( + self.live_server_url + + reverse("admin:admin_views_subscriber_change", args=(s.pk,)) + ) + object_tools = self.selenium.find_elements( + By.CSS_SELECTOR, "div#content ul.object-tools li" + ) + self.assertGreater(len(object_tools), 0) + self.take_screenshot("not-overwrap") + @override_settings(ROOT_URLCONF="admin_views.urls") class ReadonlyTest(AdminFieldExtractionMixin, TestCase):