我在索引视图中有以下代码。
latest_entry_list = Entry.objects.filter(is_published=True).order_by('-date_published')[:10]
for entry in latest_entry_list:
entry.views = entry.views + 1
entry.save()
如果从初始查询中返回了十个(限制)行,那么保存问题10是否会更新对数据库的更新调用,还是Django“智能”足以发出一次更新调用?
是否有更有效的方法来实现这一结果?
答案 0 :(得分:52)
您可以使用F()
个对象。
以下是导入F
的方式:from django.db.models import F
<强> New in Django 1.1 强>
调用更新还可以使用F()对象根据模型中另一个字段的值更新一个字段。这对于根据当前值递增计数器特别有用。
Entry.objects.filter(is_published=True).update(views=F('views')+1)
虽然您无法对切片查询集进行更新... 编辑:实际上您可以...
这可以在django ORM中完全完成。您需要两个SQL查询:
获取非切片查询集是一个难点。我想知道使用in_bulk
但是它返回一个字典,而不是一个查询集。通常会使用Q objects
来执行复杂的OR类型查询,这样可以正常工作,但pk__in
可以更简单地完成工作。
latest_entry_ids = Entry.objects.filter(is_published=True)\
.order_by('-date_published')
.values_list('id', flat=True)[:10]
non_sliced_query_set = Entry.objects.filter(pk__in=latest_entry_ids)
n = non_sliced_query_set.update(views=F('views')+1)
print n or 0, 'items updated'
由于django懒惰地执行查询的方式,无论更新了多少项,这都会导致2次数据库命中。
答案 1 :(得分:13)
您可以在单个事务中处理更新,这可以显着提高性能。使用单独的函数,用@ transaction.commit_manually装饰。
@transaction.commit_manually
def update_latest_entries(latest_entry_list):
for entry in latest_entry_list:
entry.views += 1
entry.save()
transaction.commit()
答案 2 :(得分:3)
<强>修强>
您正在更新10个单独的,不同的对象。
10个独立的,独立的,不同的更新不能轻易地折叠成一个神奇的更新,以某种方式触及10个对象。
答案 3 :(得分:3)
如果你真的需要效率,那么你必须自己下载SQL并运行更新。但是,在这种情况下,这不值得增加复杂性。
通过Django 1.1,您可以通过ORM在单个SQL调用中使用F() objects来引用更新值中的字段。
答案 4 :(得分:2)
对上一个条目的性能改进。这导致一个数据库命中,带有子查询。
latest_entry_query_set = Entry.objects.filter(is_published=True)
.order_by('-date_published')[:10]
non_sliced_query_set = Entry.objects.filter(pk__in=latest_entry_query_set.values('id'))
n = non_sliced_query_set.update(views=F('views')+1)
print n or 0, 'items updated'