Django按最新评级列出所有作者

时间:2011-08-08 00:28:21

标签: python django

鉴于Django文档中的以下简化模型,我想返回所有作者的列表,这些作者按其最近的条目评分,或者过去某个日期之前的最新作品。

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

最后我想把它变成一个python字典,如:{1star:(author1,author2),2star:(author3,author4,author5)...}。

一种想法是返回所有条目,然后使用itertools.groupby来操作大型数据集。任何人都可以提出更清洁的选择吗?

3 个答案:

答案 0 :(得分:2)

最近很难在没有大量工作的情况下在vanilla Django中完成(最大,平均等等都可以通过注释和聚合完成)。

我使用自定义管理器执行此操作:

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
                ''',
        })

然后将以下内容添加到作者模型中:

class Author():
    ...
    objects = AuthorManager()

然后,当您想要具有评级的作者时,您只需查询:

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

除了现在作者有一个recent_rating字段之外,它几乎与其他任何提取速度相同。:

for author in authors:
    print author.recent_rating

答案 1 :(得分:2)

另一种方法

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)

这是你可以做到的一种方式。基本上,您按最近的条目(在本例中为上周的条目)进行排序,然后按最旧的顺序排序,然后将值列表返回的列表转换为dict。会发生什么事情,因为它被转换为字典,而较新的条目会破坏较旧的条目,所以你最终会得到一个以作者为关键词的词典,其评级为值。

答案 2 :(得分:1)

您实际上可以在模板中完全执行此操作。这样的事情应该有效:

**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 %}

基本上,此方法使用regroup模板标记按评分对所有作者进行分组。 last过滤器应该会在每个作者的评分列表中为您提供最新的评分。在那之后,它只是一个基本的重组练习,通过评级来分解并显示每个评级的所有作者。

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

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