Fixed #30981 -- Fixed admin changelist crash when using F() or OrderBy() expressions in admin_order_field.
This commit is contained in:
parent
e9def97d10
commit
0284a26af9
|
@ -308,7 +308,12 @@ class ChangeList:
|
||||||
order_field = self.get_ordering_field(field_name)
|
order_field = self.get_ordering_field(field_name)
|
||||||
if not order_field:
|
if not order_field:
|
||||||
continue # No 'admin_order_field', skip it
|
continue # No 'admin_order_field', skip it
|
||||||
if hasattr(order_field, 'as_sql'):
|
if isinstance(order_field, OrderBy):
|
||||||
|
if pfx == '-':
|
||||||
|
order_field = order_field.copy()
|
||||||
|
order_field.reverse_ordering()
|
||||||
|
ordering.append(order_field)
|
||||||
|
elif hasattr(order_field, 'resolve_expression'):
|
||||||
# order_field is an expression.
|
# order_field is an expression.
|
||||||
ordering.append(order_field.desc() if pfx == '-' else order_field.asc())
|
ordering.append(order_field.desc() if pfx == '-' else order_field.asc())
|
||||||
# reverse order if order_field has already "-" as prefix
|
# reverse order if order_field has already "-" as prefix
|
||||||
|
|
|
@ -105,6 +105,7 @@ class ArticleAdmin(admin.ModelAdmin):
|
||||||
'content', 'date', callable_year, 'model_year', 'modeladmin_year',
|
'content', 'date', callable_year, 'model_year', 'modeladmin_year',
|
||||||
'model_year_reversed', 'section', lambda obj: obj.title,
|
'model_year_reversed', 'section', lambda obj: obj.title,
|
||||||
'order_by_expression', 'model_property_year', 'model_month',
|
'order_by_expression', 'model_property_year', 'model_month',
|
||||||
|
'order_by_f_expression', 'order_by_orderby_expression',
|
||||||
)
|
)
|
||||||
list_editable = ('section',)
|
list_editable = ('section',)
|
||||||
list_filter = ('date', 'section')
|
list_filter = ('date', 'section')
|
||||||
|
@ -122,12 +123,20 @@ class ArticleAdmin(admin.ModelAdmin):
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# These orderings aren't particularly useful but show that expressions can
|
||||||
|
# be used for admin_order_field.
|
||||||
def order_by_expression(self, obj):
|
def order_by_expression(self, obj):
|
||||||
return obj.model_year
|
return obj.model_year
|
||||||
# This ordering isn't particularly useful but shows that expressions can
|
|
||||||
# be used for admin_order_field.
|
|
||||||
order_by_expression.admin_order_field = models.F('date') + datetime.timedelta(days=3)
|
order_by_expression.admin_order_field = models.F('date') + datetime.timedelta(days=3)
|
||||||
|
|
||||||
|
def order_by_f_expression(self, obj):
|
||||||
|
return obj.model_year
|
||||||
|
order_by_f_expression.admin_order_field = models.F('date')
|
||||||
|
|
||||||
|
def order_by_orderby_expression(self, obj):
|
||||||
|
return obj.model_year
|
||||||
|
order_by_orderby_expression.admin_order_field = models.F('date').asc(nulls_last=True)
|
||||||
|
|
||||||
def changelist_view(self, request):
|
def changelist_view(self, request):
|
||||||
return super().changelist_view(request, extra_context={'extra_var': 'Hello!'})
|
return super().changelist_view(request, extra_context={'extra_var': 'Hello!'})
|
||||||
|
|
||||||
|
|
|
@ -364,11 +364,18 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_change_list_sorting_callable_query_expression(self):
|
def test_change_list_sorting_callable_query_expression(self):
|
||||||
"""
|
"""Query expressions may be used for admin_order_field."""
|
||||||
Query expressions may be used for admin_order_field. (column 9 is
|
tests = [
|
||||||
order_by_expression in ArticleAdmin).
|
('order_by_expression', 9),
|
||||||
"""
|
('order_by_f_expression', 12),
|
||||||
response = self.client.get(reverse('admin:admin_views_article_changelist'), {'o': '9'})
|
('order_by_orderby_expression', 13),
|
||||||
|
]
|
||||||
|
for admin_order_field, index in tests:
|
||||||
|
with self.subTest(admin_order_field):
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('admin:admin_views_article_changelist'),
|
||||||
|
{'o': index},
|
||||||
|
)
|
||||||
self.assertContentBefore(
|
self.assertContentBefore(
|
||||||
response, 'Oldest content', 'Middle content',
|
response, 'Oldest content', 'Middle content',
|
||||||
'Results of sorting on callable are out of order.'
|
'Results of sorting on callable are out of order.'
|
||||||
|
@ -379,7 +386,17 @@ class AdminViewBasicTest(AdminViewBasicTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_change_list_sorting_callable_query_expression_reverse(self):
|
def test_change_list_sorting_callable_query_expression_reverse(self):
|
||||||
response = self.client.get(reverse('admin:admin_views_article_changelist'), {'o': '-9'})
|
tests = [
|
||||||
|
('order_by_expression', -9),
|
||||||
|
('order_by_f_expression', -12),
|
||||||
|
('order_by_orderby_expression', -13),
|
||||||
|
]
|
||||||
|
for admin_order_field, index in tests:
|
||||||
|
with self.subTest(admin_order_field):
|
||||||
|
response = self.client.get(
|
||||||
|
reverse('admin:admin_views_article_changelist'),
|
||||||
|
{'o': index},
|
||||||
|
)
|
||||||
self.assertContentBefore(
|
self.assertContentBefore(
|
||||||
response, 'Middle content', 'Oldest content',
|
response, 'Middle content', 'Oldest content',
|
||||||
'Results of sorting on callable are out of order.'
|
'Results of sorting on callable are out of order.'
|
||||||
|
|
Loading…
Reference in New Issue