开发者

Django list all authors by most recent rating

Given the following simplified models from the Djang开发者_如何学编程o docs, I would like to return a list of all of the authors grouped by the rating on their most recent entry, or the most recent prior to some date in the past.

 class Author(models.Model):
     name = models.CharField(max_length=50)
     email = models.EmailField()

 class Entry(models.Model):
     headline = models.CharField(max_length=255)
     pub_date = models.DateTimeField()
     mod_date = models.DateTimeField()
     authors = models.ForeignKey(Author)
     rating = models.IntegerField()

Eventually I would like to turn this into a python dictionary like: {1star:(author1,author2),2star:(author3,author4,author5)...}.

One thought is to return all of the entries, then use itertools.groupby to manipulate the large dataset. Can anyone suggest a cleaner alternative?


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)
                                          .order_by('pub_date')
                                          .select_related()
                                          .values_list('author', 'rating'))

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

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(
        select={
            '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:

**Views.py**
authors = Author.objects.all()

**Template**
{% 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.

https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#regroup

https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#last

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜