Django中查询筛选数据时,大多数是使用封装好的orm,其中有一些较为复杂的sql语句很难使用orm实现,因此在此引入Django中原生sql的使用方法
在Django中使用原生Sql主要有以下三种方法:
一:extra:结果集修改器,一种提供额外查询参数的机制
二:raw:执行原始sql并返回模型实例
三:直接执行自定义Sql
下面列举django文档中的例子
from django.db import models
class Book(models.Model):
name = models.CharField('书名')
price = models.IntegerField('价钱')
publish = models.CharField('出版社')
create_time = models.DateTimeField('上线日期')
1.extra:结果集修改器,是吗一种提供额外查询参数的机制
books= Book.objects.filter(publish='清华出版社').extra(where=['price>50'])
此方法适合用于orm难以实现的某个筛选条件,将这个条件单独选出,使用原生sql进行筛选。此方法也依然主要依靠与orm
谨慎使用,防止sql注入问题
2.raw:执行原始sql并返回模型实例
raw() 自动将查询中的字段映射到模型上的字段。
books = Book.objects.raw('select * from book where publish="清华出版社"')
或者,您可以使用translations参数to 将查询中的字段映射到模型字段 raw()。这是一个字典,将查询中字段的名称映射到模型上字段的名称。例如,上面的查询也可以写成:
name_map = {'user_name': 'name', 'book_price': 'price', 'pls': 'publish', 'time': 'create_time'}
Book.objects.raw('SELECT * FROM book', translations=name_map)
此方法在执行完原生sql后,返回一个orm的实例
3.直接执行自定义Sql
from django.db import connection # django封装好的方法
cursor=connection.cursor() # 建立游标
cursor.execute("insert into book(name) values('小王子')") #插入操作
cursor.execute('update book set name='梦里花落知多少' where name='撒哈拉的故事'') #更新操作
cursor.execute('delete from book where name='小王子'') #删除操作
cursor.execute('select * from book') #查询操作
raw = cursor.fetchone() #读取一条
raw_list = cursor.fetchall() #读取所有,返回list
cursor.close() #关闭游标
另一种更好的方法,采用django文档种的语句
rom django.db import connection
def my_custom_sql(self):
with connection.cursor() as cursor: # with语句相当与cursor= connection.cursor() 和 cursor.close(),简化了语句
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
如果您使用多个数据库,则可以使用django.db.connections获取特定数据库的连接(和游标)。django.db.connections是一个类似字典的对象,允许您使用其别名检索特定连接:
from django.db import connections
with connections['my_db_alias'].cursor() as cursor:
# Your code here...
此方法是真正的完全抛弃orm,直接使用原生sql,django中也有封装好的connection方法使用,只要sql语句使用流畅,此方法也比较方便。
默认情况下,Python DB API将返回没有字段名称的结果,这意味着您最终会得到一个list值,而不是一个dict。在较小的性能和内存成本下,您可以使用以下内容返回结果dict:
def dictfetchall(cursor):
"Return all rows from a cursor as a dict"
columns = [col[0] for col in cursor.description]
return [
dict(zip(columns, row))
for row in cursor.fetchall()
]
# 结果例子
# [{'parent_id': None, 'id': 54360982}, {'parent_id': None, 'id': 54360880}]
另一种选择是使用collections.namedtuple()Python标准库。A namedtuple是一个类似元组的对象,其字段可通过属性查找访问; 它也是可索引和可迭代的。结果是不可变的,可以通过字段名称或索引访问,这可能很有用:
from collections import namedtuple
def namedtuplefetchall(cursor):
"Return all rows from a cursor as a namedtuple"
desc = cursor.description
nt_result = namedtuple('Result', [col[0] for col in desc])
return [nt_result(*row) for row in cursor.fetchall()]
# 结果例子
# [Result(id=54360982, parent_id=None), Result(id=54360880, parent_id=None)]