【python】在Django中,执行原生SQL查询

文章目录

  • 在Django中,执行原生SQL查询
    • [1. 使用 `raw()` 方法](#1. 使用 raw() 方法)
    • [2. 使用数据库连接直接执行SQL](#2. 使用数据库连接直接执行SQL)
    • [3. 使用多个数据库](#3. 使用多个数据库)
    • [4. 执行写操作(INSERT/UPDATE/DELETE)](#4. 执行写操作(INSERT/UPDATE/DELETE))
    • [5. 事务处理](#5. 事务处理)
    • [6. 实用的封装函数](#6. 实用的封装函数)
    • 注意事项

在Django中,执行原生SQL查询

1. 使用 raw() 方法

raw() 方法允许你执行原生SQL查询并返回模型实例:

python 复制代码
from myapp.models import Person

# 基本查询
people = Person.objects.raw('SELECT * FROM myapp_person WHERE age > %s', [18])

# 遍历结果
for person in people:
    print(person.name, person.age)

# 带参数的查询
people = Person.objects.raw(
    'SELECT * FROM myapp_person WHERE age BETWEEN %s AND %s',
    [20, 30]
)

2. 使用数据库连接直接执行SQL

基本用法:

python 复制代码
from django.db import connection

def my_custom_sql():
    with connection.cursor() as cursor:
        # 执行查询
        cursor.execute("SELECT * FROM myapp_person WHERE age > %s", [25])
        
        # 获取所有结果
        rows = cursor.fetchall()
        
        # 或者逐行获取
        # row = cursor.fetchone()
        # rows = cursor.fetchmany(size=10)
    
    return rows

返回字典格式的结果:

python 复制代码
from django.db import connection

def dictfetchall(cursor):
    """将游标结果转换为字典列表"""
    columns = [col[0] for col in cursor.description]
    return [
        dict(zip(columns, row))
        for row in cursor.fetchall()
    ]

def my_custom_sql():
    with connection.cursor() as cursor:
        cursor.execute("SELECT id, name, age FROM myapp_person")
        results = dictfetchall(cursor)
    return results

3. 使用多个数据库

如果你的项目配置了多个数据库:

python 复制代码
from django.db import connections

def query_multiple_dbs():
    # 使用默认数据库
    with connections['default'].cursor() as cursor:
        cursor.execute("SELECT * FROM table1")
        # 处理结果
    
    # 使用其他数据库
    with connections['other_db'].cursor() as cursor:
        cursor.execute("SELECT * FROM table2")
        # 处理结果

4. 执行写操作(INSERT/UPDATE/DELETE)

python 复制代码
from django.db import connection

def update_data():
    with connection.cursor() as cursor:
        # INSERT
        cursor.execute(
            "INSERT INTO myapp_person (name, age) VALUES (%s, %s)",
            ['John', 30]
        )
        
        # UPDATE
        cursor.execute(
            "UPDATE myapp_person SET age = %s WHERE name = %s",
            [31, 'John']
        )
        
        # DELETE
        cursor.execute(
            "DELETE FROM myapp_person WHERE age < %s",
            [18]
        )

5. 事务处理

python 复制代码
from django.db import transaction, connection

@transaction.atomic
def complex_operation():
    with connection.cursor() as cursor:
        try:
            # 一系列SQL操作
            cursor.execute("UPDATE accounts SET balance = balance - %s", [100])
            cursor.execute("UPDATE accounts SET balance = balance + %s", [100])
        except Exception as e:
            # 出错时会自动回滚
            print(f"Error: {e}")

6. 实用的封装函数

python 复制代码
from django.db import connection

def execute_query(query, params=None, return_dict=True):
    """
    执行SQL查询的通用函数
    """
    with connection.cursor() as cursor:
        cursor.execute(query, params or [])
        
        if query.strip().upper().startswith('SELECT'):
            if return_dict:
                columns = [col[0] for col in cursor.description]
                return [dict(zip(columns, row)) for row in cursor.fetchall()]
            else:
                return cursor.fetchall()
        else:
            # 对于非SELECT查询,返回受影响的行数
            return cursor.rowcount

# 使用示例
results = execute_query(
    "SELECT name, age FROM myapp_person WHERE age > %s",
    [25]
)

Django原生SQL查询 raw方法 直接数据库连接 返回模型实例 支持模型方法 自动字段映射 connection.cursor 返回原始数据 手动结果处理 执行查询 SELECT查询 写操作 fetchall fetchone fetchmany INSERT UPDATE DELETE 元组格式 字典格式转换

注意事项

  1. SQL注入防护:始终使用参数化查询,不要直接拼接字符串

    python 复制代码
    # ✅ 安全:使用参数化查询
    cursor.execute("SELECT * FROM users WHERE username = %s", [username])
    
    # ❌ 危险:字符串拼接(SQL注入风险)
    cursor.execute(f"SELECT * FROM users WHERE username = '{username}'")
    
    # ❌ 危险:直接传递用户输入
    cursor.execute("SELECT * FROM users WHERE username = %s" % username)
  2. 表名引用:在SQL中使用实际的数据库表名,而不是模型名

  3. 性能考虑 :原生SQL通常更快,但失去了Django ORM的一些便利功能;使用直接连接:需要最高性能、复杂查询或跨表查询

  4. 数据库兼容性:如果你使用多个数据库后端,要注意SQL语法的差异

这些方法让你在需要优化性能或执行复杂查询时,能够灵活地使用原生SQL,同时保持代码的安全性和可维护性。

相关推荐
一晌小贪欢24 分钟前
Python基础:第 09 篇 · while 循环:重复直到不满足
开发语言·c++·python·数据可视化·面向对象·python办公
一条大祥脚1 小时前
CuTe 与 CuTe DSL:从 C++ 模板元编程到 Python DSL 的 GPU 编程演进
开发语言·c++·python·cutlass·cute·cute dsl
10年前端老司机2 小时前
Milvus 8种检索能力实践
数据库·python·agent
Decay__2 小时前
14_MySQL 高可用与容灾架构 —— MGR / InnoDB Cluster / Keepalived+VIP / 双主 / 读写分离 / 两地三中心
运维·数据库·sql·mysql·架构
freejackman2 小时前
【实战三】撕开脱敏盲区:深度解析 CASE WHEN 与窗口函数血缘
大数据·数据库·sql
Sakura_j_h_3 小时前
从零写一个 MCP stdio Server:用 Python 校验博客文章格式
开发语言·python·自动化·ai工具·mcp·json-rpc
大草原的小灰灰3 小时前
LLM应用的标准开发框架LangChain(八)- 中间件
python·中间件·langchain
卷无止境3 小时前
百万 token 时代的真相:主流大模型上下文窗口与最大输出的横向对比分析
人工智能·python
用户298698530143 小时前
Python 实战:将 HTML 批量转换为 Markdown
python·html·markdown
hhcgchpspk4 小时前
flask服务端页面预防被爬措施
后端·python·flask·网络爬虫·防爬