Django F 表达式加入字段
Posted
技术标签:
【中文标题】Django F 表达式加入字段【英文标题】:Django F expressions joined field 【发布时间】:2014-02-21 17:24:26 【问题描述】:所以我试图通过运行以下命令来更新我的模型:
FooBar.objects.filter(something=True).update(foobar=F('foo__bar'))
但我收到以下错误:
FieldError: Joined field references are not permitted in this query
如果 F
表达式不允许这样做...我该如何实现此更新?
门票
鉴于this ticket 中的信息,我现在明白这是不可能的,并且永远不会在 django 中实现,但是有没有办法实现这个更新?也许有一些解决方法?我不想使用循环,因为有超过一千万个FooBar
对象,所以 SQL 比 python 快得多。
【问题讨论】:
【参考方案1】:Django 1.11 增加了对子查询的支持。你应该能够做到:
from django.db.models import Subquery, OuterRef
FooBar.objects.filter(something=True).update(
foobar=Subquery(FooBar.objects.filter(pk=OuterRef('pk')).values('foo__bar')[:1])
)
【讨论】:
这应该设置为接受的答案。很有帮助,谢谢! 不,它对我不起作用。我收到了这个错误:django.db.utils.OperationalError: (1093, "You can't specify target table 'xxx' for update in FROM 子句")【参考方案2】:为什么不在这里使用原始 sql: 基于this,它将类似于
from django.db import connection
raw_query = '''
update app_foobar set app_foobar.foobar =
(select app_foo.bar from app_foo where app_foo.id = app_foobar.foo_id)
where app_foobar.something = 1;
'''
cursor = connection.cursor()
cursor.execute(raw_query)
【讨论】:
这是另一种方法:"""UPDATE app_foobar b SET mycol = foo.othercol FROM app_foo a WHERE a.id = b.foo_id""".【参考方案3】:这是 Georgi Yanchev 对两个模型的回答的实现:
class Foo(models.Model):
bar = models.ForeignKey(Bar)
Foo.objects \
.filter(foo_field_1=True) \
.update(foo_field_2=Subquery(
Bar.objects \
.filter(id=OuterRef('bar_id')) \
.values('bar_field_1')[:1]))
【讨论】:
pk=OuterRef('bar')
而不是 id=OuterRef('bar_id')
对我来说效果很好,我更喜欢它,因为它只使用模型的属性 (bar
) 而不是 Django 的内部属性 (bar_id
)。跨度>
【参考方案4】:
对于任何想要一种更简单的方法并且没有大量对象的情况的人来说,下面的 sn-p 应该可以正常工作:
for fooBar in FooBar.objects.filter(something=True):
fooBar.foobar = fooBar.foo.bar
fooBar.save(update_fields=['foobar'])
对于常规用例,这不应该带来太大的性能差异,尤其是在作为数据迁移的一部分运行时。
如果需要进一步优化,您也可以选择使用select_related
。
【讨论】:
以上是关于Django F 表达式加入字段的主要内容,如果未能解决你的问题,请参考以下文章