Django 使用 raw sql
connections与connection
db.connections是一个类似字典的对象,可以通过某个数据库连接的别名获取这个数据源的connection。比如connections['my_db_alias']
from django.db import connections
for key in connections:
print(key)
# 可以打印出所有配置了的数据源别名,django会为每个数据源创建一个connection
通过django/db/init.py中
class DefaultConnectionProxy:
"""
Proxy for accessing the default DatabaseWrapper object's attributes. If you
need to access the DatabaseWrapper object itself, use
connections[DEFAULT_DB_ALIAS] instead.
"""
def __getattr__(self, item):
return getattr(connections[DEFAULT_DB_ALIAS], item)
def __setattr__(self, name, value):
return setattr(connections[DEFAULT_DB_ALIAS], name, value)
def __delattr__(self, name):
return delattr(connections[DEFAULT_DB_ALIAS], name)
def __eq__(self, other):
return connections[DEFAULT_DB_ALIAS] == other
connection = DefaultConnectionProxy()
由于DEFAULT_DB_ALIAS='default'
,可以知道from django.db import connection
获取的就是connections['default']
因此,在多数据库的情况下,可以通过connections获取特定数据库连接的queries或cursor
from django.db import connections
connections['my_db_alias'].queries
cursor = connections['my_db_alias'].cursor()
使用cursor跨库查询
前面已经提到,使用connection.cursor()
表示使用默认数据库的连接
如果有多个数据库连接配置,那么一定要用connections[db_name].cursor()
指定一个
那么在connections[db_name].cursor()
中可以查到另一个schema中的表吗?
答案是可以的
比如,我想要连接db_1的order表和db_2的product表,可以使用connections[db_1].cursor()
进行连接,然后在sql中通过db_2.product
访问db_2
sql = "select o.id from order o, db_2.product p where o.product_id=p.id and p.type=%s"
sql_values = [1]
with connections["db_1"].cursor() as cur:
cur.execute(sql, sql_values)
order_ids = [row[0] for row in cur.fetchall()]
前提是db_2与db_1在同一个MySQL的服务端上
传递cursor参数
cur.execute(sql, sql_values)
并不是简单的字符串拼接,它可以有效防止sql注入
注意以下的写法是错误的
# 直接使用字符串拼接
>>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname
>>> Person.objects.raw(query)
# 画蛇添足地使用'%s',不需要担心cursor识别不了字符串
>>> query = "SELECT * FROM myapp_person WHERE last_name = '%s'"
占位符对应的python数据类型可以是int、str、datetime、list等类型。这些类型在被整合进sql语句前都会得到正确的处理
sql = (
"select * from product where "
"created_time >= %s and type in %s and order_id = %s and device_name = %s"
)
cursor.execute(sql, [datetime.now(), [1,2], 123, "iphone"])