如何使用Django的raw方法执行SQL查询并避免常见错误?

一、raw()方法基础与典型问题场景

Django的raw()方法允许开发者直接执行原生SQL查询,返回模型实例集合。其基本语法为:

Book.objects.raw('SELECT * FROM library_book WHERE publication_date > %s', [date])

在实际使用中,开发者常遇到以下核心问题:结果集字段映射错误。当SQL查询返回的列名与模型字段不匹配时,会导致属性访问异常。例如:

  • SQL使用AS别名时未与模型字段对应
  • JOIN查询返回重复列名未显式指定
  • 聚合函数结果未正确映射

二、参数化查询与SQL注入防御

使用raw()时最大的安全隐患是SQL注入漏洞。以下为错误示范:

# 危险!直接拼接字符串
query = "SELECT * FROM auth_user WHERE username = '%s'" % request.GET['user']
User.objects.raw(query)

正确做法应使用参数化查询

  1. 使用%s占位符(PostgreSQL用%s,SQLite用?
  2. 通过第二个参数传递值列表
  3. 对动态表名使用.extra()而非字符串拼接

三、高级映射与性能优化

复杂查询时可通过以下方式优化:

场景解决方案
跨模型字段映射使用translations参数指定字段别名
自定义结果处理重写prefetch_related或定义@property
大批量数据结合iterator()流式处理

四、调试与异常处理

当查询出错时,Django会抛出django.db.utils.DatabaseError。建议:

  • 使用connection.queries查看最终执行的SQL
  • 捕获DataError处理类型转换异常
  • 对复杂查询先使用数据库客户端验证语法

典型调试流程示例:

from django.db import connection
try:
    results = Book.objects.raw(complex_query)
    [print(row) for row in results]
finally:
    print(connection.queries[-1]['sql'])