Django中的 connection.cursor() 用法
使用 Django 的底层数据库 API 来执行原生 SQL 语句。在 Django 中使用 connection.cursor()
来执行 SQL 语句。
获取游标
要执行SQL查询,首先需要获取数据库的游标:
from django.db import connection cursor = 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")
执行 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 注入。