mysql - Django:使用 LEFT JOIN 聚合原始 SQL,无外键,并注入(inject)到 DetailView(上下文)

标签 mysql django aggregate detailview rawsql

我一直在用 Django 1.7 改造我的网络应用程序。这很有趣……还有眼泪和鲜血!

过去几天我一直在努力做一个简单的 LEFT JOIN 来从没有 FK 的表中聚合一些值。查询结果应该转到类 View (DetailView)。相信我,我在整个网络(包括万维网)中搜索和搜索答案都无济于事。

您可能会问为什么我的表没有外键?好吧,最初的数据库设计没有任何内容,现在表中有数亿行。我可以添加 FK 约束,但这会很昂贵,但它会阻止事情发生,并且需要重新制作执行提取和加载的整个脚本!

我想回到美好的旧时光raw SQL因为,根据 Django 的说法,

raw() has a bunch of other options that make it very powerful...

对对对。事实是 model.objects.raw() 它的功能是有限的,它对我想做的事情不起作用(它只是不聚合)。

表格/模型(简化)

Table `customer` (customer_id, order_id) 

Table `order` (order_id, order_name)

MySQL/Django 查询(简化)

'SELECT a.order_id, SUM(a.order_value) 
FROM order a 
LEFT JOIN customer b 
ON a.order_id = b.order_id 
WHERE b.customer_id = %s', [customer_id]

看起来很天真吧?一定不行!这是 Django 的噩梦!当然,我可以在 Django 中使用 __set 轻松做到这一点,但是可惜,我没有 FK。

除了我的问题之外,我还尝试将聚合添加到我的 DetailView 模板中的上下文中。所以我尝试用 View() 破解它并在我的 DetailView 自定义类中创建一个函数:

def NewContextFTW():
    # here get the freaking queryset in my own terms
    return myhighlycomplexqueryset

然后在模板中:

{% for rows in view.NewContextFTW %}
    {{rows.id}}
    {{rows.sum_order_value}}
{% endfor %}

...但是它失败了。

编辑: 我今天找到了解决方案!我想把爱分享给世界!请参阅下面我的回答。

最佳答案

这个解决方案解决了我的问题。希望它也能解决您的问题。

覆盖get_context_data,直接通过连接执行SQL,将结果列表转换成字典,添加到上下文中,享受:

def get_context_data(self, **kwargs):
    # get context from the class this very function belongs to
    context = super(MyClassView, self).get_context_data(**kwargs)
    user = self.user # example

    cursor = connection.cursor()
    cursor.execute('SELECT a.order_id, SUM(a.order_value) FROM order a LEFT JOIN customer b ON a.order_id = b.order_id WHERE b.customer_id = %s', [user])
    d = dictfetchall(cursor)

    new_object_list = []
    for i in range(len(d)):
        order_id = d[i]['order_id']
        sum_order_value = d[i]['SUM(a.order_value)']
        row = aggregated_row(order_id, sum_order_value)
        new_object_list.append(row)

    context['aggregated_values'] = new_object_list
    return  context

要完成这项工作,请不要忘记:

from django.views.generic import DetailView
from django.db import connection

...然后定义以下函数将列表转换为字典(此样板来自 Django 1.7 自己的文档):

def dictfetchall(cursor):
    "Returns all rows from a cursor as a dict"
    desc = cursor.description
    return [
        dict(zip([col[0] for col in desc], row))
        for row in cursor.fetchall()
    ]

...创建一个类来将您的行保存为对象:

 class aggregated_row(object):
    def __init__(self, order_id, sum_order_value):
        self.order_id = order_id
        self.sum_order_value = sum_order_value

...最后但同样重要的是,模板:

{% for rows in aggregated_values%}
        <tr>
                <td>{{rows.order_id}}</td>
                <td>{{rows.sum_order_value}}</td>
        </tr>

{% endfor %}

关于mysql - Django:使用 LEFT JOIN 聚合原始 SQL,无外键,并注入(inject)到 DetailView(上下文),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28704530/

相关文章:

java - 使用 PreparedStatement 对 MySQL 中的记录进行排序

python - 如何在python中解码ascii

python - docker python 官方示例错误

nhibernate - 我在这个模型中打破了我的聚合边界吗?

MySQL查询-每天查找 "new"个用户

MySQL : collect the sum of the associated values

java - 如何将 JOOQ 配置为具有相同结构的代码生成表?

javascript - 如何使javascript中的排序函数表现得像mysql order by

django:正确检索日期和时间大于现在的数据

r - 使用 data.table (R 3.1.1) 进行字符串分组(聚合)