You can use F()
objects for this now:
New in Django Development version.
Calls to update can also use F() objects to update one field based on the value of another field in the model. This is especially useful for incrementing counters based upon their current value.
Entry.objects.filter(is_published=True).update(views=F('views')+1)
Although you can't do an update on a sliced query set... edit: actually you can...
This can be done completely in django ORM. You need two SQL queries:
- Do your filter and collect a list of primary keys
- Do an update on a non-sliced query set of items matching any of those primary keys.
Getting the non-sliced query set is the hard bit. I wondered about using in_bulk
but that returns a dictionary, not a query set. One would usually use Q objects
to do complex OR type queries and that will work, but pk__in
does the job much more simply.
latest_entry_query_set = Entry.objects.filter(is_published=True)\
.order_by('-date_published')[:10]
latest_entry_ids = (ent.pk for ent in latest_entry_query_set) #iterator
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'
Due to the way that django executes queries lazily, this results in just 2 database hits, no matter how many items are updated.