Django 1.0/1.1 重写自加入
Posted
技术标签:
【中文标题】Django 1.0/1.1 重写自加入【英文标题】:Django 1.0/1.1 rewrite of self join 【发布时间】:2010-10-11 08:44:08 【问题描述】:有没有办法使用 Django QuerySet 对象重写这个查询:
SELECT b.created_on, SUM(a.vote)
FROM votes a JOIN votes b ON a.created_on <= b.created_on
WHERE a.object_id = 1
GROUP BY 1
其中 votes 是一个表,object_id 是一个多次出现的 int(外键 - 虽然在这里无关紧要),而 created_on 是一个日期时间。
FWIW,此查询允许人们在过去的任何时间通过汇总之前对该 object_id 的所有投票来获得分数。
【问题讨论】:
【参考方案1】:我很确定无法使用 Django ORM 创建查询。新的 Django 聚合代码非常灵活,但我认为它不能完全满足您的要求。
您确定该查询有效吗?您似乎错过了 b.object_id 为 1 的检查。
这段代码应该可以工作,但它不止一行而且效率不高。
from django.db.models import Sum
v_list = votes.objects.filter(object__id=1)
for v in v_list:
v.previous_score = votes.objects.filter(object__id=1, created_on__lte=v.created_on).aggregate(Sum('vote'))["vote__sum"]
聚合仅在主干中可用,因此您可能需要先更新 django 安装才能执行此操作。
【讨论】:
你的可能是最接近的可能性 - 但正如你所说,效率低下。我决定直接使用 .extra() 执行 sql。【参考方案2】:聚合不是问题;这里的问题是 Django 的 ORM 根本不会对任何不是 ForeignKey、AFAIK 的东西进行连接。
【讨论】:
【参考方案3】:这就是我现在使用的。具有讽刺意味的是,sql 被破坏了,但这是它的要点:
def get_score_over_time(self, obj):
"""
Get a dictionary containing the score and number of votes
at all times historically
"""
import pdb; pdb.set_trace();
ctype = ContentType.objects.get_for_model(obj)
try:
query = """SELECT b.created_on, SUM(a.vote)
FROM %s a JOIN %s b
ON a.created_on <= b.created_on
WHERE a.object_id = %s
AND a.content_type_id = %s
GROUP BY 1""" % (
connection.ops.quote_name(self.model._meta.db_table),
connection.ops.quote_name(self.model._meta.db_table),
1,
ctype.id,
)
cursor = connection.cursor()
cursor.execute(query)
result_list = []
for row in cursor.fetchall():
result_list.append(row)
except models.ObjectDoesNotExist:
result_list = None
return result_list
【讨论】:
以上是关于Django 1.0/1.1 重写自加入的主要内容,如果未能解决你的问题,请参考以下文章
django写商业网站的时候用户系统是自己重写还是用自带的?