【问题标题】:Using annotate or extra to add field of foreignkey to queryset ? (equivalent of SQL "AS" ?)使用 annotate 或 extra 将外键字段添加到查询集? (相当于 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 实例。但只是想检查是否有更好的方法?

谢谢你,

迈克尔

【问题讨论】:

    标签: python django django-queryset django-orm


    【解决方案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'}),但它不起作用!

    【讨论】:

    猜你喜欢
    • 2018-03-10
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 2014-01-18
    • 2011-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多