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

参考文档

https://docs.djangoproject.com/en/3.1/topics/db/sql/

posted @ 2020-09-08 18:37  luozx207  阅读(1556)  评论(0编辑  收藏  举报