TL / DR: Да, ваше решение, кажется, следует единственному подходу, который имеет смысл.
Хорошо, то, что вы здесь сочли, кажется рекомендуемым способом изисточники, которые вы перечислили в своем вопросе и по уважительной причине.
В чем причина?
Я не нашел в этом коде окончательного ответа, но япредставьте, что это связано с тем, как @property
декоратор работает в Python.
Когда мы устанавливаем свойство с помощью декоратора, мы не можем добавлять к нему атрибуты, а поскольку admin_order_field
является атрибутом, у нас его там не может быть. Это утверждение, по-видимому, подкреплено документацией Администратора Django list_display
, где существует следующий отрывок:
Элементы list_display
также могут быть свойствами. Однако обратите внимание, что из-за того, как свойства работают в Python, установка short_description
для свойства возможна только при использовании функции property()
, а не с декоратором @property
.
Эта цитата в сочетании с этим QA: AttributeError: объект 'property' не имеет атрибута 'admin_order_field' , кажется, объясняет, почему невозможно получить заказ из свойства модели непосредственно вПанель администратора.
Это объяснило (вероятно?), что пришло время для некоторой умственной гимнастики !!
В ранее упомянутой части документации мы также видим, что admin_order_field
может принимать выражения запроса начиная с версии 2.1:
Выражения запроса могут использоваться в admin_order_field. Например:
from django.db.models import Value
from django.db.models.functions import Concat
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def full_name(self):
return self.first_name + ' ' + self.last_name
full_name.admin_order_field = Concat('first_name', Value(' '), 'last_name')
Это в сочетании с предыдущей частью о методе property()
позволяет нам реорганизовать ваш код и существенно переместить часть annotation
в модель:
class De(models.Model):
...
def calculate_s_d(self):
if self.fr:
return self.de
else:
return self.gd + self.na
calculate_s_d.admin_order_field = Case(
When(fr=True, then='s_d'),
When(fr=False, then=F('gd') + F('na')),
default=Value(0),
output_field=IntegerField(),
)
s_d = property(calculate_s_d)
Наконец, на admin.py
нам нужно только:
class DeAdmin(admin.ModelAdmin):
list_display = ("[...]", "s_d")