I am trying to do this:
UserLog.objects.filter(user=user).filter(action=\'message\').filter(timestamp__lt=now)[0:5].update(read=True)
but I
As the error states, you cannot call update()
on a QuerySet if you took out a slice.
The reason:
LIMIT
statement in SQL.UPDATE
statement.What you are trying to do would be equivalent to
UPDATE ... WHERE ... LIMIT 5
which is not possible, at least not with standard SQL.
Your code is incorrect because of where the slicing happens. It should happen after the call to update()
, not before.
Wrong:
UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now)[0:5].update(read=True)
Right:
UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now).update(read=True)[0:5]
I was getting the same error when attempting to limit the number of records returned by a queryset.
I found that if we're using one of Django's class-based generic views such as the ArchiveIndexView, we can use the paginate_by =
attribute to limit the number of records.
For example (in 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
If you want to slice out some of the results of a queryset, you can copy it it to another variable (a shallow copy is enough, which is faster than a deep copy because it just uses references to the original objects.)
import copy
queryset = Mytable.objects.all()
pieceOfQuery = copy.copy(queryset)
pieceOfQuery = pieceOfQuery[:10]
This will keep Django from complaining if you have an order_by filter on your table, since that happens after the slicing if you do it on the main queryset object
You can't do that. From the Django documents: QuerySet API reference - update
The documentation suggests that something like the following might be possible - I'm not sure if doing the limiting in an inner QuerySet
bypasses the check around calling update()
after slicing:
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)
Failing that, you could use the in field lookup like so:
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)