dav*_*gan 7 python sql django django-orm
我正在建立一个Django网站进行讨论.用户可以参与讨论,也可以在讨论中投票批准讨论和消息.简化的数据模型如下:
class Discussion:
name = models.CharField(max_length=255)
class Message:
owner = models.ForeignKey(User, related_name='messages')
body = models.TextField()
discussion = models.ForeignKey(Discussion, related_name='messages')
class MessageApprovalVote:
owner = models.ForeignKey(User, related_name='message_approval_votes')
message = models.ForeignKey(Message, related_name='approval_votes')
class DiscussionApprovalVote:
owner = models.ForeignKey(User, related_name='discussion_approval_votes')
discussion = models.ForeignKey(Discussion, related_name='approval_votes')
Run Code Online (Sandbox Code Playgroud)
我想选择前20个"最活跃"的讨论,这意味着按消息数量,消息批准投票总数和讨论的讨论批准投票数量之和进行排序,或者(以伪代码形式):
# Doesn't work
Discussion.objects.
order_by(Count('messages') +
Count('approval_votes') +
Count('messages__approval_votes'))
Run Code Online (Sandbox Code Playgroud)
使用注释,我可以计算三个评分因子中每一个的总数:
scores = Discussion.objects.annotate(
total_messages=Count('messages', distinct=True),
total_discussion_approval_votes=Count('approval_votes', distinct=True),
total_message_approval_votes=Count('messages__approval_votes', distinct=True))
Run Code Online (Sandbox Code Playgroud)
当我找到extra方法时,我认为我正在做某事:
total_scores = scores.extra(
select={
'score_total': 'total_messages + total_discussion_approval_votes + total_message_approval_votes'
}
)
Run Code Online (Sandbox Code Playgroud)
然后能够做到:
final_answer = total_scores.order_by('-score_total')[:20]
Run Code Online (Sandbox Code Playgroud)
但是extra电话给出了DatabaseError:
DatabaseError: column "total_messages" does not exist
LINE 1: SELECT (total_votes + total_messages + total_persuasions) AS...
Run Code Online (Sandbox Code Playgroud)
因此我被挫败了.该extra方法可以不引用annotated字段吗?有没有其他方法可以做我正在尝试做的事情,没有使用原始的SQL查询?如果有所作为,我正在使用Postgres.
任何见解将不胜感激!
我认为这在单个顶级 SQL 查询中是不可能的。Score_total 值取决于三个聚合结果,但您要求同时计算它们。
在直接 SQL 中,您可以使用子查询来完成此操作,但我不确定如何将其注入到 Django 中。使用模型设置简单的 Django 应用程序后,以下查询似乎可以针对 SQLite 数据库完成任务:
SELECT id, name,
total_messages, total_discussion_approval_votes, total_message_approval_votes,
(total_messages +
total_discussion_approval_votes +
total_message_approval_votes) as score_total
FROM
(SELECT
discussion.id,
discussion.name,
COUNT(DISTINCT discussionapprovalvote.id) AS total_discussion_approval_votes,
COUNT(DISTINCT messageapprovalvote.id) AS total_message_approval_votes,
COUNT(DISTINCT message.id) AS total_messages
FROM discussion
LEFT OUTER JOIN discussionapprovalvote
ON (discussion.id = discussionapprovalvote.discussion_id)
LEFT OUTER JOIN message
ON (discussion.id = message.discussion_id)
LEFT OUTER JOIN messageapprovalvote
ON (message.id = messageapprovalvote.message_id)
GROUP BY discussion.id, discussion.name)
ORDER BY score_total DESC
LIMIT 20;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1012 次 |
| 最近记录: |