在 Django 开发中,通常依赖于 Django ORM 来处理数据库操作,它提供了一个高级的抽象层,使得数据库交互更加直观和安全。然而,有时可能需执行一些复杂的查询或数据库操作,这些操作可能超出了 ORM 的能力范围(比如动态生成DB表结构等等)。在这些情况下,可以使用 Django 的底层数据库 API 来执行原生 SQL 语句。本文将介绍如何在 Django 中使用 connection.cursor()
来执行 SQL 语句。
Django 的数据库连接
获取游标
要执行SQL查询,首先需要获取数据库的游标:
from django.db import connectioncursor = connection.cursor()
执行查询
有了游标,才可执行SQL查询:
cursor.execute("SELECT * FROM my_table")
处理结果
执行查询后,你可以使用 fetchone()
、fetchmany()
或 fetchall()
方法来检索结果:
rows = cursor.fetchall() # 读取所有数据,下面有介绍其他方法
for row in rows:print(row)print(row[0])
关闭游标
完成数据库操作后,应关闭游标以释放资源:
cursor.close()
使用上下文管理器(推荐)
为简化资源管理,推荐使用 with
语句作为上下文管理器,会在代码块执行完毕后自动关闭游标:
with connection.cursor() as cursor:cursor.execute("SELECT * FROM my_table")
更多connection.cursor() 执行 SQL 用法
执行 SQL 查询
有了游标对象,可用它来执行 SQL 查询。以下是一个执行 SELECT 查询的例子:
cursor.execute("SELECT * FROM myapp_mymodel")
你也可以使用参数化查询来防止 SQL 注入攻击:
cursor.execute("SELECT * FROM myapp_mymodel WHERE id = %s", [some_id])
获取查询结果
执行查询后,你可以使用游标的 fetchone()
、fetchmany()
或 fetchall()
方法来检索结果。
# 获取单个结果
row = cursor.fetchone()# 获取多个结果(可以指定数量)
rows = cursor.fetchmany(size=5)# 获取所有结果
rows = cursor.fetchall()
一些读取操作:
# 读取
for tup in cursor.fetchall():data.append({"id": tup[0], "name": tup[1], "teach_id": tup[2], "teacher_name": tup[3], "content": tup[4]})# 判断
one = cursor.fetchone()
if one is not None:return Response({'message': f'{one[0]}已存在'}, status=status.HTTP_400_BAD_REQUEST)
但有发现,返回的都是一个列表,而无法直接用数据库表字段名锁定,这是有个其他方法,能锁定到字段名对应的索引列。
columns = {col[0]: idx for idx, col in enumerate(cursor.description)}print(columns)
# {'create_time': 0, 'update_time': 1, 'uid': 2, 'task_uid': 3, 'usage': 4, 'type': 5}
# k-v 为 字段名-索引# 获取所有行
rows = cursor.fetchall()
for row in rows:# 使用列名来访问数据name = row[columns['name']]print(name)
执行事务
在执行更新、删除或插入操作时,你可能需要使用事务来确保数据的一致性。Django 默认在每个请求的末尾自动提交事务,但你可以手动控制事务的提交和回滚(在执行 INSERT、UPDATE 或 DELETE 操作时,大可能控制事务的提交和回滚):
try:with connection.cursor() as cursor:# 执行SQL查询cursor.execute("UPDATE my_table SET field = %s WHERE another_field = %s", ['new_value', 'some_value'])# 提交更改connection.commit() except Exception as err:# 发生异常,回滚事务connection.rollback()print("An error occurred: ", err)
注:
- 用 SQL 查询可能会绕过 Django 的安全和验证机制,因此需要谨慎处理输入。
- 原生 SQL 查询时,确保查询与你的数据库后端兼容。
- 用
connection.cursor()
时,记得遵循数据库的最佳实践,比如使用参数化查询来防止 SQL 注入。