Подтвердить что ты не робот

Django: увеличение количества записей в блоге на единицу. Является ли это эффективным?

В моем индексном представлении есть следующий код.

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 "smart" достаточно, чтобы выпустить только один вызов обновления?

Есть ли более эффективный метод для достижения этого результата?

4b9b3361

Ответ 1

Вы можете использовать для этого объекты F().

Вот как вы импортируете F: from django.db.models import F

Новое в Django 1.1.
Вызовы для обновления также могут использовать объекты F() для обновления одного поля на основе значения другого поля в модели. Это особенно полезно для увеличения счетчиков на основе их текущего значения.

Entry.objects.filter(is_published=True).update(views=F('views')+1)

Хотя вы не можете выполнить обновление в наборе заданных наборов... edit: на самом деле вы можете...

Это можно сделать полностью в ORM django. Вам нужны два 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

Вы можете обрабатывать обновления в одной транзакции, что может значительно повысить производительность. Используйте отдельную функцию, украшенную @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()

Ответ 3

Исправленный вариант

Вы обновляете 10 отдельных, отдельных, отдельных объектов.

10 отдельных отдельных отдельных изменений не могут быть легко свернуты в одно волшебное обновление, которое каким-то образом затрагивает 10 объектов.

Ответ 4

Если вам действительно нужна эффективность, на данный момент вам придется спуститься в SQL и запустить обновление самостоятельно. Тем не менее, это не стоит добавленной сложности.

По Django 1.1 вы сможете сделать это в одном вызове SQL через ORM, используя F() objects для ссылок на поля в значении обновления.

Ответ 5

Улучшение производительности предыдущей записи. Это приводит к одному удалению базы данных с подзапросом.

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'