mirror of
https://github.com/django/django.git
synced 2024-12-23 01:25:58 +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:
parent
4ade8386eb
commit
9cefdfc43f
@ -18,6 +18,7 @@ from django.contrib.admin.views.main import (
|
|||||||
)
|
)
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
@ -112,7 +113,7 @@ def result_headers(cl):
|
|||||||
# Set ordering for attr that is a property, if defined.
|
# Set ordering for attr that is a property, if defined.
|
||||||
if isinstance(attr, property) and hasattr(attr, "fget"):
|
if isinstance(attr, property) and hasattr(attr, "fget"):
|
||||||
admin_order_field = getattr(attr.fget, "admin_order_field", None)
|
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
|
is_field_sortable = False
|
||||||
|
|
||||||
if not is_field_sortable:
|
if not is_field_sortable:
|
||||||
|
@ -3,7 +3,7 @@ from django.contrib.auth.admin import UserAdmin
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.paginator import Paginator
|
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")
|
site = admin.AdminSite(name="admin")
|
||||||
|
|
||||||
@ -57,6 +57,9 @@ class GrandChildAdmin(admin.ModelAdmin):
|
|||||||
list_display = ["name", "parent__name", "parent__parent__name"]
|
list_display = ["name", "parent__name", "parent__parent__name"]
|
||||||
|
|
||||||
|
|
||||||
|
site.register(GrandChild, GrandChildAdmin)
|
||||||
|
|
||||||
|
|
||||||
class CustomPaginationAdmin(ChildAdmin):
|
class CustomPaginationAdmin(ChildAdmin):
|
||||||
paginator = CustomPaginator
|
paginator = CustomPaginator
|
||||||
|
|
||||||
|
@ -2073,3 +2073,59 @@ class SeleniumTests(AdminSeleniumTestCase):
|
|||||||
By.CSS_SELECTOR, "[data-filter-title='It\\'s OK']"
|
By.CSS_SELECTOR, "[data-filter-title='It\\'s OK']"
|
||||||
).get_attribute("open")
|
).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)
|
||||||
|
Loading…
Reference in New Issue
Block a user