Refs #29428 -- Fixed admin check crash when using a query expression in ModelAdmin.ordering.

This commit is contained in:
Tim Graham 2018-06-14 14:47:20 -04:00
parent 0d8e3e608e
commit ec2c9c3531
3 changed files with 30 additions and 1 deletions

View File

@ -10,6 +10,7 @@ from django.core import checks
from django.core.exceptions import FieldDoesNotExist from django.core.exceptions import FieldDoesNotExist
from django.db import models from django.db import models
from django.db.models.constants import LOOKUP_SEP from django.db.models.constants import LOOKUP_SEP
from django.db.models.expressions import Combinable, F, OrderBy
from django.forms.models import ( from django.forms.models import (
BaseModelForm, BaseModelFormSet, _get_foreign_key, BaseModelForm, BaseModelFormSet, _get_foreign_key,
) )
@ -489,7 +490,13 @@ class BaseModelAdminChecks:
def _check_ordering_item(self, obj, model, field_name, label): def _check_ordering_item(self, obj, model, field_name, label):
""" Check that `ordering` refers to existing fields. """ """ Check that `ordering` refers to existing fields. """
if isinstance(field_name, (Combinable, OrderBy)):
if not isinstance(field_name, OrderBy):
field_name = field_name.asc()
if isinstance(field_name.expression, F):
field_name = field_name.expression.name
else:
return []
if field_name == '?' and len(obj.ordering) != 1: if field_name == '?' and len(obj.ordering) != 1:
return [ return [
checks.Error( checks.Error(

View File

@ -11,3 +11,6 @@ Bugfixes
* Fixed admin changelist crash when using a query expression without ``asc()`` * Fixed admin changelist crash when using a query expression without ``asc()``
or ``desc()`` in the page's ordering (:ticket:`29428`). or ``desc()`` in the page's ordering (:ticket:`29428`).
* Fixed admin check crash when using a query expression in
``ModelAdmin.ordering`` (:ticket:`29428`).

View File

@ -3,6 +3,8 @@ from django.contrib.admin import BooleanFieldListFilter, SimpleListFilter
from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline from django.contrib.admin.options import VERTICAL, ModelAdmin, TabularInline
from django.contrib.admin.sites import AdminSite from django.contrib.admin.sites import AdminSite
from django.core.checks import Error from django.core.checks import Error
from django.db.models import F
from django.db.models.functions import Upper
from django.forms.models import BaseModelFormSet from django.forms.models import BaseModelFormSet
from django.test import SimpleTestCase from django.test import SimpleTestCase
@ -829,6 +831,23 @@ class OrderingCheckTests(CheckTestCase):
self.assertIsValid(TestModelAdmin, ValidationTestModel) self.assertIsValid(TestModelAdmin, ValidationTestModel)
def test_invalid_expression(self):
class TestModelAdmin(ModelAdmin):
ordering = (F('nonexistent'), )
self.assertIsInvalid(
TestModelAdmin, ValidationTestModel,
"The value of 'ordering[0]' refers to 'nonexistent', which is not "
"an attribute of 'modeladmin.ValidationTestModel'.",
'admin.E033'
)
def test_valid_expression(self):
class TestModelAdmin(ModelAdmin):
ordering = (Upper('name'), Upper('band__name').desc())
self.assertIsValid(TestModelAdmin, ValidationTestModel)
class ListSelectRelatedCheckTests(CheckTestCase): class ListSelectRelatedCheckTests(CheckTestCase):