django/python:多表的原始SQL

3 投票
2 回答
4888 浏览
提问于 2025-04-17 04:28

我需要在多个表上执行原始 SQL 查询,然后把结果显示出来。对于一个表,我会这样做:

sql = "select * from my_table"
results = my_table.objects.raw(sql)

对于多个表,我是这样做的:

sql = "select * from my_table, my_other_table where ...."
results = big_model.objects.raw(sql)

但是,我真的需要创建一个包含所有可能需要字段的大模型吗?我实际上并不会在这个“表”中存储任何数据。

补充说明:

我有一个表叫 my_users,还有一个表叫 my_listings。这些表在 Models.py 中定义。my_listings 表有一个外键指向 my_users,表示是谁创建了这个列表。

SQL 查询是:

"select user_name, listing_text from my_listings, my_users where my_users.id = my_listings.my_user_id". 

我希望这个 SQL 查询能生成一个结果集,以便我可以在 Django 中渲染我的页面。

我的问题是:我必须创建一个包含 user_name 和 listing_text 字段的模型吗?还是有更好的方法可以继续使用原始 SQL(select, from, where)?当然,我实际的查询比这个例子要复杂得多。(我在 models.py 中定义的模型会变成数据库中的实际表,所以我才用模型/表这个说法。不知道还有什么其他的说法,抱歉。)我使用原始 SQL 是因为我发现 Python 的表引用只适用于简单的数据模型。

2 个回答

0

你并不需要一个包含你想从原始SQL中返回的字段的模型。如果恰好你有一个模型,里面有你想要的字段,那么你可以把原始SQL的输出映射到这个模型上。否则,你可以使用游标,完全不使用模型。

2
  1. 这个方法有效。不知道之前为什么不行 :( 根据Dennis Baker的评论:

你并不需要一个包含所有字段的模型,只需要第一个模型和它的字段就可以了。你需要确保字段的名称是唯一的,尽量使用“tablename.field as fieldname”这种写法来确保字段名不重复。我用这种方法做过一些比较复杂的查询,涉及5个以上的表,结果总是能和一个单一的模型关联起来。

另外一个解决方案是使用游标。不过,游标需要从元组列表转换成字典列表。我相信使用迭代器会有更简洁的方法,但这个函数是可以工作的。它接收一个字符串,也就是原始的SQL查询,然后返回一个可以在模板中渲染和使用的列表。

from django.db import connection, transaction

def sql_select(sql):
    cursor = connection.cursor()
    cursor.execute(sql)
    results = cursor.fetchall()
    list = []
    i = 0
    for row in results:
        dict = {} 
        field = 0
        while True:
           try:
                dict[cursor.description[field][0]] = str(results[i][field])
                field = field +1
            except IndexError as e:
                break
        i = i + 1
        list.append(dict) 
    return list  

撰写回答