Django 提供了两种形式来执行原生 SQL 代码。
一种是应用 raw() 函数,一种是 应用 connection.cursor()。
然而官网还是举荐在应用原生 SQL 之前,尽量的先去摸索一下 QuerySet 提供的各种 API。
目前而言,官网文档提供的各种 API 是可能满足绝大多数的利用场景的。
以下是本篇笔记的目录:
- raw()
- connection.cursor()
- 多数据库操作
1、raw()
这个办法能够用来操作原生 SQL,而后返回 model 实例:
咱们以 Blog 作为示例,应用的代码如下:
for blog in Blog.objects.raw("select * from blog_blog"):
print(blog)
下面这段代码的作用成果跟 Blog.objects.all() 获取的后果是一样的,然而在一些操作上又不太一样,比方 all().count() 能够获取到 总数,然而 raw() 就不能进行这种操作。
须要留神的是,raw() 并不会去检测输出的 SQL 代码 ,即便咱们应用 Blog 这个 model 来查问 Entry 的数据,也可能返回后果,不过返回的都是 Entry 表的属性:
for blog in Blog.objects.raw("select * from blog_entry"):
print(blog.__dict__) # __dict__ 输入的都是 blog_entry 的字段
也就是说 在 Blog.objects.raw() 中,真正起作用的只有 raw() 这一个函数,后面的 Blog 不过是一个架子,或者路径,是为了引出 raw() 这个函数。
自定义返回字段
在 raw() 函数的 SQL 代码里,咱们能够自定义选中的字段,如果须要应用没有选中的字段,那么零碎会再次拜访数据库来获取,这个操作过程就跟后面介绍的 defer() 函数一样。
for item in Blog.objects.raw("select id from blog_blog"):
print(item.__dict__)
print(item.id, item.name)
print(item.__dict__)
{'_state': <django.db.models.base.ModelState object at 0x7fbd4165b6a0>, 'id': 2}
2 hunter
{'_state': <django.db.models.base.ModelState object at 0x7fbd4165b6a0>, 'id': 2, 'name': 'hunter'}
能够看到,返回的后果中先输入的数据只有 id,前面,当咱们拜访 name 字段的时候,又去获取了 name 字段的数据。
自定义字段必须蕴含主键
当咱们自定义字段返回的时候,必须是要蕴含主键字段的,否则在咱们获取信息的时候会报错,比方上面的操作:
for blog in Blog.objects.raw("select name from blog_blog"):
print(blog.__dict__)
在 print(blog.__dict__) 的时候就会报错,数据中没有主键信息
自定义返回新字段
能够跟 QuerySet 的 annotate 操作一样,自定义新字段返回,获取的时候能够间接依据属性值返回,比方:
entry = Entry.objects.raw("select *, date_format(pub_date,'%%Y-%%m') as date_1 from blog_entry")[0]
print(entry.date_1)
传递变量
给输出的 SQL 语句传递变量:
name = "python"
Blog.objects.raw("select * from blog_blog where name ='%s'", [name])
2、connection.cursor()
Django 推出了一种更加间接执行 SQL 的形式,用到的模块是 django.db.connction,用到的 cursor 和 pymysql 的库是一样的用法,官网给出的示例如下:
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
须要留神,如果有参数传入 SQL 中,须要对一些符号进行本义之后才能够应用,比方:
cursor.execute("SELECT foo FROM bar WHERE baz ='30%'")
cursor.execute("SELECT foo FROM bar WHERE baz ='30%%'AND id = %s", [self.id])
其中,第二条语句的 % 须要进行本义
适配 fetch 的数据
通过 fetchone 和 fetchall() 返回的数据是只有 value 值的,没有对应的字段 key,如果能够适当的就义性能和内存,来换取获取数据的便当和准确性,官网提供了这样一种形式:
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()]
在咱们执行完 cursor.execute(sql) 之后,把 cursor 作为参数传入 dictfetchall 函数中,就能够返回一个字典列表
介绍一下 cursor.description,这个返回的是一个元组数据,外面的元素也是一个元组,元组的第一个元素就是咱们 select 的字段名。
所以 columns = [col[0] for col in cursor.description] 这一行代码获取的是指定的所有字段名
应用示例:
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()]
with connection.cursor() as cursor:
sql = "select id, name from blog_blog"
cursor.execute(sql)
results = dictfetchall(cursor)
print(results)
# 返回的后果:# [{'id': 20, 'name': 'name_3'}, {'id': 21, 'name': 'name_4'}, {'id': 1, 'name': 'name_5'}]
在我应用的过程中,咱们应用的是上下文管理器的形式来获取游标:
with connection.cursor() as cursor:
cursor.execute()
所以,应用完之后,不须要手动敞开,他与上面的用法成果是统一的:
c = connection.cursor()
try:
c.execute(...)
finally:
c.close()
但举荐的还是上下文管理器的形式,更优雅。
3、多数据库操作
如果零碎用到了多个数据库,那么在应用 cursor 的时候,就须要应用到 django.db.connections 模块:
from django.db import connections
with connections['my_db_alias'].cursor() as cursor:
pass
以上就是本篇笔记全部内容,下一篇笔记将简略介绍一下多数据库的操作。
本文首发于自己微信公众号:Django 笔记。
原文链接:Django 笔记二十一之应用原生 SQL 查询数据库
如果想获取更多相干文章,可扫码关注浏览: