Django:将博客条目视图增加一个。这有效吗?

时间:2009-01-15 15:15:31

标签: python database django performance

我在索引视图中有以下代码。

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“智能”足以发出一次更新调用?

是否有更有效的方法来实现这一结果?

5 个答案:

答案 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查询:

  1. 执行过滤并收集主键列表
  2. 对与任何主键匹配的非切片查询集进行更新。
  3. 获取非切片查询集是一个难点。我想知道使用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'