django官方文档——执行原始sql查询
来源:互联网 发布:大数据统计学就业前景 编辑:程序博客网 时间:2024/04/26 22:15
执行原始 SQL 查询¶
当你觉得 模型查询 API 还不够用时,你可以使用原始 SQL 。 Django 中有两种方式可以执行原始 SQL :你可以使用 Manager.raw() 来执行原始查询并返回模型实例 ,或者你可以完全避开模型层 直接执行定制的SQL 。
执行原始查询¶
管理器的 raw() 方法可以用于执行原始 SQL 并返回模型实例:
- Manager.raw(raw_query,params=None, translations=None)¶
这个方法执行一个原始 SQL 查询并返回一个 RawQuerySet 实例。这个RawQuerySet 实例是可迭代的,就象通常的查询集一样可以提供对象实例。
来个例子就容易明白了,假设你有下面的模型:
class Person(models.Model): first_name = models.CharField(...) last_name = models.CharField(...) birth_date = models.DateField(...)
你可以象这样执行定制的 SQL
>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):... print pJohn SmithJane Jones
当然这个例子不是十分有趣,只是相当于运行了 Person.objects.all() 。但是,raw() 有一大把的相当给力的参数。
模型表名称
上例中 Person 表的名称是什么?
缺省情况下, Django 把模型的“应用标签”(你在 manage.pystartapp 中使用的名称)和模型的类名称用下划线连接起来作为一个数据库表名。在上例中,我们假设 Person 模型在名称 myapp 的应用中,所以它的表名是myapp_person 。
详情参见 db_table 选项的文档。这个选项还可以让你手动指定数据库表名。
Warning
传递给 .raw() 的 SQL 语句是不经过 Django 查验的。 Django 会指望从数据库中返回一组行,但这不是强迫性的。如果查询没有返回行,那么可以会产生一个(可能是隐性的)错误。
映射查询字段到模型字段¶
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')...
映射是根据名字进行的。你可以使用 SQL 的 AS 子句来进行映射,因此如果你有一些其他包含Person 数据的表,那么可以轻易地与 Person 实例相映射:
>>> Person.objects.raw('''SELECT first AS first_name,... last AS last_name,... bd AS birth_date,... pk as id,... FROM some_other_table''')
当名称一致时,模型实例就会正确创建。
还有一种方法,你可以使用 raw() 的translations 参数来进行映射。这个参数是一个映射查询字段名称和模型字段名称的字典。上述的查询也可以写成:
>>> name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}>>> Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
索引查找¶
raw() 支持索引,因此如果你只需要第一个结果,可以这样:
>>> first_person = Person.objects.raw('SELECT * from myapp_person')[0]
但是,索引和切片不是在数据库级别执行的。如果你在数据库中有大量的 Person 对象,那么在 SQL 级别来限制查询更有效率:
>>> first_person = Person.objects.raw('SELECT * from myapp_person LIMIT 1')[0]
延迟模型字段¶
字段也可以是不完全的:
>>> people = Person.objects.raw('SELECT id, first_name FROM myapp_person')
本例中查询返回的 Person 对象将会是延迟模型实例( (参见defer() )。也就是说在查询中省略的字段会在需要是载入。例如:
>>> for p in Person.objects.raw('SELECT id, first_name FROM myapp_person'):... print p.first_name, # This will be retrieved by the original query... print p.last_name # This will be retrieved on demand...John SmithJane Jones
从表面看,好像查询同时获取了名和姓。但是,这个例子实际发出了三个查询。原始查询只获取了名,而两个姓是在打印时分别获取的。
唯一不能省略的字段是主键。 Django 使用主键来判别模型实例,所以在一个原始查询中必须包含主键,否则会抛出一个 InvalidQuery 异常。
加入统计¶
你也可以执行包含模型中没有的字段的查询。例如,我们可以使用 PostgreSQL 的 age() 函数 来让数据库统计出人员的年龄:
>>> people = Person.objects.raw('SELECT *, age(birth_date) AS age FROM myapp_person')>>> for p in people:... print "%s is %s." % (p.first_name, p.age)John is 37.Jane is 42....
向 raw() 传递参数¶
如果你需要执行带参数的查询,你可以使用 params 参数:
>>> lname = 'Doe'>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])
params 是一个参数列表。在查询字符串中你要使用%s 占位符(不管你用何种数据库引擎)。占位符会被params 列表中的参数代替。
Warning
不要在原始查询中使用格式化字符串!
你可能将上文的查询写成这样:
>>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname>>> Person.objects.raw(query)
千万不要这样做。
使用 params 列表可以保护你避开SQL 注入攻击 (通过漏洞把恶意 SQL 注入你的数据库)。如果你使用了字符串插入,那么尽早你会成为 SQL 注入的受害者,因此请谨记使用params 列表。
直接执行定制的SQL¶
有时候,甚至 Manager.raw() 还是不够用:你可能需要执行不明确对应模型的查询或者直接执行UPDATE 、 INSERT 或 DELETE 查询。
在这种情况下,你可以直接操作数据库,完全绕开模型层。
django.db.connection 对象表现缺省数据库连接,django.db.transaction 表现缺省数据库事务。要使用数据库连接可以调用connection.cursor() 来得到一个指针对象。然后,就可以调用cursor.execute(sql, [params]) 来执行 SQL 和 cursor.fetchone() 或cursor.fetchall() 来返回结果行。在执行一个改变数据的操作后,你应当调用transaction.commit_unless_managed() 来确保你的改变被提交。如果只是获取数据就不必提交了。例如:
def my_custom_sql(): from django.db import connection, transaction cursor = connection.cursor() # Data modifying operation - commit required cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz]) transaction.commit_unless_managed() # Data retrieval operation - no commit required 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 connectionscursor = connections['my_db_alias'].cursor()# Your code here...transaction.commit_unless_managed(using='my_db_alias')
事务和原始 SQL¶
当你执行了原始 SQL 之后, Django 会自动把当前事务放入黑箱。你必须确保事务正确结束。详见 Django 的事务处理需求注意点 。
Django 1.3 版之前,当使用原始 SQL 时必须通过 transaction.set_dirty() 手动把事务放入黑箱。
连接和指针¶
连接 和 指针 大多数执行标准 Python DB-API (除非是为了 事务处理 )。如果你不熟悉 Python DB-API ,那么要注意 cursor.execute() 中的 SQL 语句使用占位符"%s" 比直接在 SQL 中添加参数要好。如果你使用了这个技术,那么基础数据库会根据需要为你的参数自动添加引号和转义符。这样做是符合一致性原则的,并且是一种聪明的作法。(还要注意 Django 使用"%s" 作为占位符,而 不是"?" 。)
- django官方文档——执行原始sql查询
- django 1.8 官方文档翻译: 2-5-2 进行原始的sql查询
- django官方文档——统计查询
- django官方文档——统计查询
- django执行原始SQL
- Django执行原始SQL
- Django执行原始SQL
- [Django] 查看orm自动执行的原始查询sql
- django执行原始查询sql,并返回Dict字典
- django 1.8 官方文档翻译: 2-2-1 执行查询
- django官方文档——Django settings
- django官方文档——构造查询(数据库查询 查询数据库)
- django官方文档——发送邮件
- django官方文档——Settings详解
- django官方文档——django中的用户认证
- Django学习8—数据库使用3-原始sql使用
- django官方文档——模型与数据库
- django官方文档——管理器(数据库操作接口)
- Java EE Servlet监听器
- 不同时钟域的时序问题
- shell基础1:文件安全与权限
- speex库的使用
- SQLite3 C/C++介绍
- django官方文档——执行原始sql查询
- C#实现office文档转换为PDF或xps的一些方法
- 基于hash方法的相似计算
- webservice中wsdl文件说明
- Web.config中的特殊字符
- MinHash算法
- Java反射编程的小例子
- linux的system () 函数详解
- 为何Google比苹果和微软更需要HTML5?