首页 > 解决方案 > Django基于另一个模型字段注释值

问题描述

我有这两个模型,案例和专业,就像这样:

class Case(models.Model):
   ...
   judge = models.CharField()
   ....

class Specialty(models.Model):
   name = models.CharField()
   sys_num = models.IntegerField()

我知道这听起来像一个非常奇怪的结构,但试着告诉我:模型judge中的字段Case引用一个Specialty实例sys_num值(judge是一个字符字段,但它总是带有一个整数)(每个Specialty实例都有一个唯一的sys_num)。因此,我可以使用以下方式获取Specialty与特定Case实例相关的名称:

my_pk = #some number here...
my_case_judge = Case.objects.get(pk=my_pk).judge
my_specialty_name = Specialty.objects.get(sys_num=my_case_judge)

我知道这听起来很奇怪,但我无法更改表的底层架构,只需使用 sql 和 Django 的 orm 解决它。

我的问题是:我想在已经调用的查询集中注释Specialty名称。Casesvalues()

我只是设法让它工作CaseWhen但它不是动态的。如果我添加更多Specialty实例,我将不得不手动更改代码。

 cases.annotate(
         specialty=Case(
             When(judge=0, then=Value('name 0 goes here')),
             When(judge=1, then=Value('name 1 goes here')),
             When(judge=2, then=Value('name 2 goes here')),
             When(judge=3, then=Value('name 3 goes here')),
             ...

这可以动态完成吗?我查看了django 的查询参考文档,但无法使用那里指定的工具生成有效的解决方案。

标签: pythonmysqldjangodjango-orm

解决方案


您可以使用子查询表达式执行此操作:

from django.db.models import OuterRef, Subquery

Case.objects.annotate(
    specialty=Subquery(
        Specialty.objects.filter(sys_num=OuterRef('judge')).values('name')[:1]
    )
)

对于某些数据库,甚至可能需要强制转换:

from django.db.models import IntegerField, OuterRef, Subquery
from django.db.models.functions import Cast

Case.objects.annotate(
    specialty=Subquery(
        Specialty.objects.filter(sys_num=Cast(
            OuterRef('judge'),
            output_field=IntegerField()
        )).values('name')[:1]
    )
)

但是造型很差。通常最好使用 a ForeignKey,这将保证judgecan 只指向一个有效的案例(因此引用完整性),将在字段上创建索引,并且它还将使 Django ORM 更有效,因为它允许更高级的查询使用(相对)小查询。


推荐阅读