一、Manager.raw

(raw_query, params=None, translations=None)
此方法接受原始SQL查询,执行该查询,然后返回django.db.models.query.RawQuerySet实例。可以像普通QuerySet一样迭代此RawQuerySet实例以提供对象实例。
例如:
class Person(models.Model):
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    birth_date = models.DateField(...)

>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
...     print(p)
John Smith
Jane Jones
注意:原生sql语句中使用的是数据库中的实际表名,而不是model名。
使用raw()的几大特点:
• 自动将查询中的字段映射到模型上的字段,查询中字段的顺序无关紧要。下面两种结果相同。
>>> Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')
...
>>> Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person')
...
• 支持对结果集的索引。
first_person = Person.objects.raw('SELECT * FROM myapp_person')[0]

'''但是,索引和切片不是在数据库级别执行的。'''
'''如果数据库中有大量的Person对象,则在SQL级别限制查询会更有效'''

first_person = Person.objects.raw('SELECT * FROM myapp_person LIMIT 1')[0]
• 传参数
如果需要执行参数化查询,则可以对raw()使用params参数。
lname = 'Doe'
Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])
params是参数的列表或字典,您将在查询字符串中将%s占位符用于列表,或将%(key)s占位符用于字典(其中键由字典键替换),无论您的数据库引擎如何。此类占位符将被params参数中的参数替换。
注意:SQLite后端不支持字典参数。使用此后端,您必须将参数作为列表传递。
警告1:
• 不要在原始查询中使用字符串格式,也不要在SQL字符串中引用占位符!
# 错误思路1
>>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname
>>> Person.objects.raw(query)

# 错误思路2(您可能还认为应该这样编写查询(用引号引起来的%s))
>>> query = "SELECT * FROM myapp_person WHERE last_name = '%s'"
使用params参数并且不使用占位符会保护您免受SQL注入攻击。
警告2:
• 传递给.raw()的SQL语句不做任何检查,Django期望该语句将从数据库中返回一组行,但是不执行任何操作。如果查询不返回行,则将导致(可能是神秘的)错误。
• 如果要在MySQL上执行查询,请注意,混合类型时,MySQL的静默类型强制可能会导致意外结果。如果在字符串类型的列上查询但具有整数值,MySQL将在执行比较之前将表中所有值的类型强制为整数,例如,如果您的表包含值“ abc”,“ def”,并且您查询WHERE mycolumn = 0,则两行都将匹配。为避免这种情况,请在查询中使用该值之前执行正确的类型转换。
二、直接执行自定义SQL
from django.db import connection

def my_custom_sql(self):
    with connection.cursor() as cursor:
        cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
        cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
        row = cursor.fetchone()

    return row