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)