1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Refs #10743 -- Enabled ordering for lookups in ModelAdmin.list_display.

Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Co-authored-by: Nina Menezes <https://github.com/nmenezes0>
This commit is contained in:
Tom Carrick 2023-11-16 09:11:27 +01:00 committed by Natalia
parent 4ade8386eb
commit 9cefdfc43f
3 changed files with 62 additions and 2 deletions

View File

@ -18,6 +18,7 @@ from django.contrib.admin.views.main import (
)
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.constants import LOOKUP_SEP
from django.template import Library
from django.template.loader import get_template
from django.templatetags.static import static
@ -112,7 +113,7 @@ def result_headers(cl):
# Set ordering for attr that is a property, if defined.
if isinstance(attr, property) and hasattr(attr, "fget"):
admin_order_field = getattr(attr.fget, "admin_order_field", None)
if not admin_order_field:
if not admin_order_field and LOOKUP_SEP not in field_name:
is_field_sortable = False
if not is_field_sortable:

View File

@ -3,7 +3,7 @@ from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django.core.paginator import Paginator
from .models import Band, Child, Event, Parent, ProxyUser, Swallow
from .models import Band, Child, Event, GrandChild, Parent, ProxyUser, Swallow
site = admin.AdminSite(name="admin")
@ -57,6 +57,9 @@ class GrandChildAdmin(admin.ModelAdmin):
list_display = ["name", "parent__name", "parent__parent__name"]
site.register(GrandChild, GrandChildAdmin)
class CustomPaginationAdmin(ChildAdmin):
paginator = CustomPaginator

View File

@ -2073,3 +2073,59 @@ class SeleniumTests(AdminSeleniumTestCase):
By.CSS_SELECTOR, "[data-filter-title='It\\'s OK']"
).get_attribute("open")
)
def test_list_display_ordering(self):
from selenium.webdriver.common.by import By
parent_a = Parent.objects.create(name="Parent A")
child_l = Child.objects.create(name="Child L", parent=None)
child_m = Child.objects.create(name="Child M", parent=parent_a)
GrandChild.objects.create(name="Grandchild X", parent=child_m)
GrandChild.objects.create(name="Grandchild Y", parent=child_l)
GrandChild.objects.create(name="Grandchild Z", parent=None)
self.admin_login(username="super", password="secret")
changelist_url = reverse("admin:admin_changelist_grandchild_changelist")
self.selenium.get(self.live_server_url + changelist_url)
def find_result_row_texts():
table = self.selenium.find_element(By.ID, "result_list")
# Drop header from the result list
return [row.text for row in table.find_elements(By.TAG_NAME, "tr")][1:]
def expected_from_queryset(qs):
return [
" ".join("-" if i is None else i for i in item)
for item in qs.values_list(
"name", "parent__name", "parent__parent__name"
)
]
cases = [
# Order ascending by `name`.
("th.sortable.column-name", ("name",)),
# Order descending by `name`.
("th.sortable.column-name", ("-name",)),
# Order ascending by `parent__name`.
("th.sortable.column-parent__name", ("parent__name", "-name")),
# Order descending by `parent__name`.
("th.sortable.column-parent__name", ("-parent__name", "-name")),
# Order ascending by `parent__parent__name`.
(
"th.sortable.column-parent__parent__name",
("parent__parent__name", "-parent__name", "-name"),
),
# Order descending by `parent__parent__name`.
(
"th.sortable.column-parent__parent__name",
("-parent__parent__name", "-parent__name", "-name"),
),
]
for css_selector, ordering in cases:
with self.subTest(ordering=ordering):
# self.selenium.get(self.live_server_url + changelist_url)
self.selenium.find_element(By.CSS_SELECTOR, css_selector).click()
expected = expected_from_queryset(
GrandChild.objects.all().order_by(*ordering)
)
self.assertEqual(find_result_row_texts(), expected)