Django中的 connection.cursor() 用法

django2024-12-1810

使用 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 注入。