Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
195 views
in Technique[技术] by (71.8m points)

python - Django: Increment blog entry view count by one. Is this efficient?

I have the following code in my index view.

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()

If there are ten (the limit) rows returned from the initial query, will the save issue 10 seperate updated calls to the database, or is Django "smart" enough to issue just one update call?

Is there a more efficient method to achieve this result?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can use F() objects for this.

Here is how you import F: from django.db.models import F

New in Django 1.1.
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:

  1. Do your filter and collect a list of primary keys
  2. 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_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'

Due to the way that django executes queries lazily, this results in just 2 database hits, no matter how many items are updated.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...