[Django]-Django list all authors by most recent rating


Another approach

from collections import defaultdict
from datetime import datetime, timedelta

week_ago = datetime.now() - timedelta(days=7)

author_recent_ratings = dict(Entry.objects.filter(pub_date__gt=week_ago)
                                          .values_list('author', 'rating'))

recent_by_rating = defaultdict(list)
for author, rating in author_recent_ratings.iteritems():

This is one way you could do it. Basically you order by most recent entries (in this case entries from the last week) then order by oldest first, and then you convert the list returned by values list into a dict. What happens is, as it’s converted into a dict and the newer entries clobber the older ones so you end up with a dict that has authors as keys, with their ratings as the values.


Recent is hard to do in vanilla Django without a lot of work (max, average, etc. can all be done with annotations and aggregations).

I do this with a custom manager something like:

class AuthorManager(models.Manager):
  def with_recent_rating(self):
    return super(AuthorManager, self).get_query_set().extra(
            'recent_rating': '''
                SELECT e.rating
                FROM myapp_entry e
                WHERE e.authors_id = myapp_author.id
                ORDER BY e.pub_date DESC
                LIMIT 1

Then add the following to the Author model:

class Author():
    objects = AuthorManager()

Then when you want authors with the ratings you just query:

authors = Author.objects.with_recent_rating().filter(...)

It’s practically the same speed as any other fetch except now the authors have a recent_rating field.:

for author in authors:
    print author.recent_rating


You could actually do this entirely in your template. Something like this should work:

authors = Author.objects.all()

{% regroup authors by rating_set.all|last as rating_list %}

{% for rating in rating_list %}
    <b>{{ rating.grouper }}</b><br>
    {% for author in rating.list %}
        {{ author.name }}<br>
    {% endfor %}
{% endfor %}

Basically this method groups all of your authors by rating using the regroup template tag. The last filter should give you the most recent rating in the list of each author’s ratings. After that it’s just a basic regroup exercise to break it down by rating and display all the authors for each rating.



Leave a comment