使用 annotate 或 extra 将外键字段添加到查询集? (相当于 SQL“AS”?)

Posted

技术标签:

【中文标题】使用 annotate 或 extra 将外键字段添加到查询集? (相当于 SQL“AS”?)【英文标题】:Using annotate or extra to add field of foreignkey to queryset ? (equivalent of SQL "AS" ?) 【发布时间】:2015-11-03 04:12:07 【问题描述】:

我已经合并了两个单独工作的查询集(qs1 和 qs2),如下所示:

qlist = [qs1, qs2]
results = list(chain(qs1, qs2))

到目前为止,一切都很好 - 以上工作。但现在我正在尝试使用以下命令对结果进行排序:

qlist = [qs1, qs2]
results = sorted(chain(qs1, qs2), key=attrgetter('monthly_fee'))

问题是第二个查询集(qs2)通过ForeignKey引用monthly_fee;而 qs1 有 'monthly_fee' 可用。这是qs2:

qs2 = Offer.objects.select_related('subscription') 
qs2 = qs2.order_by(subscription__monthly_fee) 

以及简化模型:

class Subscription(models.Model): 
    monthly_fee = models.IntegerField(null=False, blank=True, default=0) 
    name = models.CharField(max_length=120, null=True, blank=True)

class Offer(models.Model): 
    promotion_name = models.CharField(max_length=120, null=True, blank=True)
    subscription = models.ForeignKey(Subscription)
    discount = models.IntegerField(null=False, blank=True, default=0) 

我尝试使用 .annotate() 和 .extra() 在查询 qs2 中重命名subscription__monthly_fee,如下所示:

qs2 = Offer.objects.select_related('subscription').annotate(monthly_fee=subscription__monthly_fee)

然后得到错误

全局名称“订阅__monthly_fee”未定义

我只是通过重写模型的 .save() 方法来破解这个问题,以便在创建对象时手动将monthly_fee 添加到每个 Offer 实例。但只是想检查是否有更好的方法?

谢谢你,

迈克尔

【问题讨论】:

【参考方案1】:

我以前使用 F 表达式来实现这种重命名。试试这个:

from django.db.models import F

qs2 = Offer.objects.select_related('subscription').annotate(monthly_fee=F('subscription__monthly_fee'))

【讨论】:

谢谢马克。以前从未使用过 F 表达式。尝试添加它但得到以下错误:'F' object has no attribute 'lookup' 这可能在 Django 1.8 中已修复。请参阅文档:You can also use the double underscore notation to span relationships in an F() object (docs.djangoproject.com/en/1.8/topics/db/queries/…)。【参考方案2】:

好的,我找到了一种方法来做到这一点。

qs2 = Offer.objects.select_related('subscription').extra(select='monthly_fee':'mobile_subscription.monthly_fee')

其中“mobile”是 Django 应用程序的名称。我没有意识到 .extra 允许您遵循外键,但您实际上必须指定实际的数据库表并使用 SQL 点表示法。

以上是我们应该做的实际正确的方法吗? (即删除原始 SQL 表名/字段)

我一直在尝试使用 Django 语法,例如 .extra(select='monthly_fee':'subscription__monthly_fee'),但它不起作用!

【讨论】:

这不是 Django 风格。更喜欢Mark Galloway's answer的方法。

以上是关于使用 annotate 或 extra 将外键字段添加到查询集? (相当于 SQL“AS”?)的主要内容,如果未能解决你的问题,请参考以下文章

Django如何将外键传递给ModelForm字段

如何在 Spring 中从将外键作为长属性引用的 json 创建模型?

Django将外键限制为满足特定条件的记录

通过 post 将外键的 id 传递给表单

JOOQ:如何将外键解析为对象?

使用 Visual Studio 数据库项目中的数据将外键约束添加到现有表