Django: невозможно обновить запрос после того, как был сделан фрагмент
Я пытаюсь сделать это:
UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now)[0:5].update(read=True)
но я получаю эту ошибку:
Cannot update a query once a slice has been taken.
(используя django 1.2.1)
Что я делаю неправильно?
Ответы
Ответ 1
Как говорится в ошибке, вы не можете вызвать update()
в QuerySet, если вы извлекли фрагмент.
Причина:
- Взятие среза эквивалентно оператору
LIMIT
в SQL.
- Выдача обновления превращает ваш запрос в оператор
UPDATE
.
То, что вы пытаетесь сделать, будет эквивалентно
UPDATE ... WHERE ... LIMIT 5
что невозможно, по крайней мере, не со стандартным SQL.
Ответ 2
В документации можно сделать что-то вроде следующего: я не уверен, выполняю ли ограничение во внутренних обходах QuerySet
проверка вокруг вызова update()
после нарезки:
inner_q = UserLog.objects.filter(user=user,
action='message',
timestamp__lt=now).values('pk')[0:5]
UserLog.objects.filter(pk__in=inner_q).update(read=True)
В противном случае вы можете использовать поиск in
следующим образом:
ids = UserLog.objects.filter(user=user,
action='message',
timestamp__lt=now).values_list('pk', flat=True)[0:5]
UserLog.objects.filter(pk__in=list(ids)).update(read=True)
Ответ 3
Я получал ту же ошибку при попытке ограничить количество записей, возвращаемых набором запросов.
Я обнаружил, что если мы используем один из Django общие представления на основе классов, такие как ArchiveIndexView, мы можем использовать атрибут paginate_by =
, чтобы ограничить количество записей.
Например (в views.py):
from django.views.generic import ArchiveIndexView
from .models import Entry
class HomeListView(ArchiveIndexView):
""" Blog Homepage """
model = Entry
date_field = 'pub_date'
template_name = 'appname/home.html'
queryset = Entry.objects.filter(
is_active=True).order_by('-pub_date', 'title')
paginate_by = 30
Ответ 4
Вы не можете этого сделать. Из документов Django: Ссылка на API QuerySet - обновление
Ответ 5
Если вы хотите отрезать некоторые результаты запроса, вы можете скопировать его
это к другой переменной (достаточно мелкой копии, которая быстрее
чем глубокая копия, потому что она просто использует ссылки на оригинал
объекты.)
import copy
queryset = Mytable.objects.all()
pieceOfQuery = copy.copy(queryset)
pieceOfQuery = pieceOfQuery[:10]
Это заставит Django жаловаться, если у вас есть фильтр order_by.
ваш стол, так как это происходит после нарезки, если вы делаете это на главном
объект запроса