python - 如何在 Django Admin 中实现计算模型属性的排序,而无需编写两次逻辑?

标签 python django django-admin

在我的 Django model 中,我定义了一个 @property ,它工作得很好,并且该属性可以在管理 list_display 中显示,没有任何问题。

我不仅在管理中需要此属性,而且在其他地方的代码逻辑中也需要此属性,因此将其作为我的模型的属性是有意义的。

现在我想让这个属性的列可排序,并在 the Django documentation of the When object 的帮助下, this StackOverflow question for the F()-calculationthis link for the sorting我成功构建了如下所示的工作解决方案。

在这里提出问题的原因是:事实上,我实现了我的逻辑两次,一次用Python,一次以表达式的形式,这违反了相同逻辑只实现一次的设计规则。所以我想问一下我是否错过了更好的解决方案来解决我的问题。任何想法都值得赞赏。

这是模型(标识符已修改):

class De(models.Model):

    fr = models.BooleanField("[...]")
    de = models.SmallIntegerField("[...]")
    gd = models.SmallIntegerField("[...]")
    na = models.SmallIntegerField("[...]")
    # [several_attributes, Meta, __str__() removed for readability]

    @property
    def s_d(self):
        if self.fr:
            return self.de
        else:
            return self.gd + self.na

这是模型管理员:

class DeAdmin(admin.ModelAdmin):
    list_display = ("[...]", "s_d", "gd", "na", "de", "fr" )

    def get_queryset(self, request):
        queryset = super().get_queryset(request)
        queryset = queryset.annotate(
            _s_d=Case(
                When(fr=True, then='s_d'),
                When(fr=False, then=F('gd') + F('na')),
                default=Value(0),
                output_field=IntegerField(),
            )
        )
        return queryset

    def s_d(self, obj):
        return obj._s_d
    s_d.admin_order_field = '_s_d'

如果没有其他办法,我也希望确认事实作为答案。

最佳答案

TL/DR:是的,您的解决方案似乎遵循唯一有意义的方式。

<小时/>

嗯,您在此处撰写的内容似乎是您在问题中列出的来源中推荐的方式,并且有充分的理由。

充分的理由是什么?
我还没有在代码库中找到明确的答案,但我想这与 @property 装饰器在 Python 中的工作方式有关。

当我们使用装饰器设置属性时,我们无法向其添加属性,并且由于 admin_order_field 是一个属性,因此我们不能将其添加到其中。 Django Admin's list_display documentation 似乎强化了这一说法。其中存在以下段落:

Elements of list_display can also be properties. Please note however, that due to the way properties work in Python, setting short_description on a property is only possible when using the property() function and not with the @property decorator.

该引用与此质量检查相结合:AttributeError: 'property' object has no attribute 'admin_order_field'似乎解释了为什么无法将模型属性中的可订购项直接放入管理面板中。

<小时/>

这就解释了(可能?)是时候进行一些心理体操了!!

previously mentioned part of the documentation我们还可以看到,从 2.1 版本开始,admin_order_field 可以接受查询表达式:

Query expressions may be used in admin_order_field. For example:

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")

关于python - 如何在 Django Admin 中实现计算模型属性的排序,而无需编写两次逻辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58366953/

相关文章:

python - Django Admin 将我的外键显示为中间模型作为文本输入

python multiprocessing starmap vs apply_async,哪个更快?

python - 除非导入,否则 distutils.spawn 不可用

python - 获取列表中最小项目的索引

python - TemplateDoesNotExist 在/base.html

python - (TypeError : expected string or bytes-like object) when calling function in Django

django - 如何在 Django admin `list_display` 中显示外键和多对多字段?

python - 如何在 Django 2.0 中正确设置 autocomplete_fields?

python - 在不使用 celery 的情况下在特定时间后执行python函数

python - 在 Django admin 中对内联进行单元测试验证