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"])