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字典,像这样:{1星:(作者1, 作者2), 2星:(作者3, 作者4, 作者5)...}。
我想到的一个办法是先获取所有的作品,然后用itertools.groupby来处理这个大数据集。有没有人能推荐一个更简单的方法呢?
3 个回答
其实你可以完全在模板里做到这一点。像这样应该就可以了:
**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
在普通的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
另一种方法
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)
这是一种可以实现的方法。简单来说,你可以先按照最近的记录排序(在这个例子中是过去一周的记录),然后再按照最旧的记录排在前面。接着,你把返回的值列表转换成一个字典。这样做的结果是,当转换成字典时,新记录会覆盖旧记录,最终你得到的字典中,作者是键,他们的评分是值。