Python Django:将计算应用于查询集
我有一个查询集,希望传递给通用视图进行分页:Python Django:将计算应用于查询集,python,django,algorithm,sorting,Python,Django,Algorithm,Sorting,我有一个查询集,希望传递给通用视图进行分页: links = Link.objects.annotate(votes=Count('vote')).order_by('-created')[:300] 这是我的“热门”页面,其中列出了我最近提交的300份意见书(10页,每页30个链接)。现在,我想按照HackerNews使用的算法对该查询集进行排序: (p - 1) / (t + 2)^1.5 p = votes minus submitter's initial vote t = age o
links = Link.objects.annotate(votes=Count('vote')).order_by('-created')[:300]
这是我的“热门”页面,其中列出了我最近提交的300份意见书(10页,每页30个链接)。现在,我想按照HackerNews使用的算法对该查询集进行排序:
(p - 1) / (t + 2)^1.5
p = votes minus submitter's initial vote
t = age of submission in hours
现在,因为在整个数据库中应用此算法将花费相当大的成本,我只满足于最后300次提交。我的网站不太可能成为下一个digg/reddit,因此,尽管可扩展性是一个加号,但它是必需的
我现在的问题是,如何迭代查询集并按照上述算法对其排序
有关更多信息,以下是我的适用车型:
class Link(models.Model):
category = models.ForeignKey(Category, blank=False, default=1)
user = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
url = models.URLField(max_length=1024, unique=True, verify_exists=True)
name = models.CharField(max_length=512)
def __unicode__(self):
return u'%s (%s)' % (self.name, self.url)
class Vote(models.Model):
link = models.ForeignKey(Link)
user = models.ForeignKey(User)
created = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return u'%s vote for %s' % (self.user, self.link)
注:
links = Link.objects.annotate(votes=Count('vote')).order_by('-created')[:300]
for link in links:
link.popularity = ((link.votes - 1) / (2 + 2)**1.5)
但就我的一生而言,我无法将其转化为我的模板:
{% for link in object_list %}
Popularity: {{ link.popularity }}
{% endfor %}
为什么它没有出现?我知道人气在起作用,因为:
print 'LinkID: %s - Votes: %s - Popularity: %s' % (link.id, link.votes, link.popularity)
返回我在控制台中期望的值。如果可能,您可以从查询集中创建一个值dict或值列表,并将排序算法应用于获取的dict(列表)。 看 示例
# select links
links = Link.objects.annotate(votes=Count('vote')).order_by('-created')[:300]
# make a values list:
links = links.values_list('id', 'votes', 'created')
# now sort
# TODO: you need to properly format your created date (x[2]) here
list(links).sort(key = lambda x: (x[1] - 1) / (x[2] + 2)^1.5)
其中,s
应该从计算出的最高重要度开始排序,排在第一位,排在最后一位,如下所示:
[(计算重要性,obj),(计算重要性,obj),…]
虽然无法通过查询集进行计算,但我必须转换为排序列表
links = Link.objects.select_related().annotate(votes=Count('vote'))
for link in links:
delta_in_hours = (int(datetime.now().strftime("%s")) - int(link.created.strftime("%s"))) / 3600
link.popularity = ((link.votes - 1) / (delta_in_hours + 2)**1.5)
links = sorted(links, key=lambda x: x.popularity, reverse=True)
不是最优的,但它是有效的。我不能用我可爱的对象列表通用视图自动分页,不得不求助于手动操作,但这是一个公平的折衷方案,可以使用工作视图…麻烦您提供一个例子吗?可能会在每个
投票
值中添加1。我很难理解这个概念。谢谢你的例子!虽然'ValuesListQuerySet'对象没有属性“sort”
我是否缺少导入?嗯,我想这是因为它不是一个完整的列表,为什么排序不是一个可用的选项。走近我想:keyrerror at/links/1
HmmBut我会说我需要将我的QS传递给一个通用视图,所以我不确定将其转化为列表是最好的选项。因为我正在通过一个通用视图将这个计算出的列表传递给我的模板,我认为它需要保持QS。不要使用通用视图作为解决方案。编写自己的视图很容易,它在上下文中返回排序列表,我认为不需要对5项进行分页。也许还可以在数据库级别上使用raw()
来实现这一点,从而使数据库计算流行度并按其排序。在数据库级别上进行此操作已被证明是。。。。困难。虽然人们通过使用.extra提供了这个问题的答案,但它们实际上似乎不起作用。raw()的工作原理与extra稍有不同,它返回纯SQL的查询集。我认为使用SQL会更快。哈哈,唉,我想我得去拿开发版了。
links = Link.objects.select_related().annotate(votes=Count('vote'))
for link in links:
delta_in_hours = (int(datetime.now().strftime("%s")) - int(link.created.strftime("%s"))) / 3600
link.popularity = ((link.votes - 1) / (delta_in_hours + 2)**1.5)
links = sorted(links, key=lambda x: x.popularity, reverse=True)