Django文档阅读之执行原始SQL查询
Django提供了两种执行原始SQL查询的方法:可以使用Manager.raw()来执行原始查询并返回模型实例,或者可以完全避免模型层直接执行自定义SQL。
每次编写原始SQL时都要关注防止SQL注入
一、raw()方法
raw()方法可以用来执行返回模型实例原始的SQL查询:
Manager.raw(raw_query,params = None,translations = None)
此方法接受原始SQL查询,执行它并返回 django.db.models.query.RawQuerySet实例。RawQuerySet可以像正常一样迭代此实例 QuerySet以提供对象实例。
Person.objects.raw('SELECT * FROM myapp_person')
将查询字段映射到模型字段
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''')
只要名称匹配,就会正确创建模型实例。
或者,您可以使用translations参数to 将查询中的字段映射到模型字段 raw()。这是一个字典,将查询中字段的名称映射到模型上字段的名称。例如,上面的查询也可以写成:
>>> 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]
Django使用主键来标识模型实例,因此它必须始终包含在原始查询中。一InvalidQuery,如果你忘了,包括主键,将引发异常。
将参数传递给raw()
如果需要执行参数化查询,可以使用以下params 参数raw():
>>> lname = 'Doe'
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])
params是参数的列表或字典。无论您的数据库引擎如何,您都将%s 在查询字符串中使用占位符作为列表,或者%(key)s 使用字典的占位符(当然,这key将替换为字典键)。这些占位符将替换为参数中的params 参数。
不要在原始查询上使用字符串格式或在SQL字符串中引用占位符!
将上述查询编写为:
>>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname
>>> Person.objects.raw(query)
您可能还认为应该像这样编写查询(带引号%s):
>>> query = "SELECT * FROM myapp_person WHERE last_name = '%s'"
不要犯这些错误。
使用params 参数并保留占位符不加引号可以保护您免受SQL注入攻击,这是攻击者将任意SQL注入数据库的常见漏洞。如果使用字符串插值或引用占位符,则存在SQL注入的风险。
直接执行自定义
该对象django.db.connection表示默认数据库连接。要使用数据库连接,请调用connection.cursor()以获取游标对象。然后,调用执行SQL和或返回结果行。
cursor.execute(sql,[params])
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注入,不得%s 在SQL字符串中的占位符周围包含引号。
请注意,如果要在查询中包含文字百分号,则必须在传递参数的情况下将它们加倍:
cursor.execute("SELECT foo FROM bar WHERE baz = '30%'")
cursor.execute("SELECT foo FROM bar WHERE baz = '30%%' AND id = %s", [self.id])
默认情况下,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()
]
另一种选择是使用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()]
以下是三者之间差异的一个例子:
>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2");
>>> cursor.fetchall()
((54360982, None), (54360880, None))
>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2");
>>> dictfetchall(cursor)
[{'parent_id': None, 'id': 54360982}, {'parent_id': None, 'id': 54360880}]
>>> cursor.execute("SELECT id, parent_id FROM test LIMIT 2");
>>> results = namedtuplefetchall(cursor)
>>> results
[Result(id=54360982, parent_id=None), Result(id=54360880, parent_id=None)]
>>> results[0].id
54360982
>>> results[0][0]
54360982
Django文档阅读之执行原始SQL查询的更多相关文章
- Django文档阅读-Day2
Django文档阅读 - Day2 Writing your first Django app, part 1 You can tell Django is installed and which v ...
- Django文档阅读-Day1
Django文档阅读-Day1 Django at a glance Design your model from djano.db import models #数据库操作API位置 class R ...
- Django文档阅读-Day3
Django文档阅读-Day3 Writing your first Django app, part 3 Overview A view is a "type" of Web p ...
- Django文档阅读之模型
模型 模型是您的数据唯一而且准确的信息来源.它包含您正在储存的数据的重要字段和行为.一般来说,每一个模型都映射一个数据库表. 基础: 每个模型都是一个 Python 的类,这些类继承 django.d ...
- Django文档阅读之查询
创建对象 为了在Python对象中表示数据库表数据,Django使用直观的系统:模型类表示数据库表,该类的实例表示数据库表中的特定记录. 要创建对象,请使用模型类的关键字参数对其进行实例化,然后调用s ...
- 吴裕雄--天生自然PythonDjangoWeb企业开发:Django文档阅读简介
Django是基于MVC模式的框架,虽然也被称为“MTV”的模式,但是大同小异.对我们来说,需要了解的是无论是MVC模式还是MTV模式,甚至是其他的什么模式,都是为了解耦.把一个软件系统划分为一层一层 ...
- Django文档阅读之聚合
聚合 我们将引用以下模型.这些模型用来记录多个网上书店的库存. from django.db import models class Author(models.Model): name = mode ...
- 在django中,执行原始sql语句
extra()方法 结果集修改器,一种提供额外查询参数的机制 使用extra: 1:Book.objects.filter(publisher__name='广东人员出版社').extra(where ...
- django系列5.4--ORM中执行原生SQL语句, Python脚本中调用django环境
ORM执行原生sql语句 在模型查询API不够用的情况下,我们还可以使用原始的SQL语句进行查询. Django 提供两种方法使用原始SQL进行查询:一种是使用raw()方法,进行原始SQL查询并返回 ...
随机推荐
- Boosting and AdaBoost
Boosting是一种从一些弱分类器中创建一个强分类器的集成技术(提升算法). 它先由训练数据构建一个模型,然后创建第二个模型来尝试纠正第一个模型的错误.不断添加模型,直到训练集完美预测或已经添加到数 ...
- php 常用操作数组函数
我们有很多操作数组的元素,我们这一节先讲一些.在6.3里面我们会总结更多的数组常用函数.深圳dd马达 下面的几个主要是移动数组指针和压入弹出数组元素的和个函数. 函数 功能 array_shift 弹 ...
- A - Happy Birthday, Polycarp!
Codeforces Round #606 (Div. 2, based on Technocup 2020 Elimination Round 4) A. Happy Birthday, Polyc ...
- 洛谷 P2341 [HAOI2006]受欢迎的牛 题解
今天学了强连通分量的Tarjan算法,做了这道类似于板子题的题(尽管我调了1.5h).主要的思路是用Tarjan缩点之后,求每个点的入度(实际上是出度,因为我是反着连边的).如果 有且只有一个点的入度 ...
- 每个开发人员必须知道PDB文件知识
大多数开发人员都意识到PDB文件有助于您进行调试,但仅此而已.如果你不知道PDB文件是怎么回事,不要觉得很糟糕,因为虽然有文档在那里,但它分散在周围,而且大部分是为编译器和调试器编写器准备的.虽然编写 ...
- 文件搜索命令find
1.路径加文件名搜索(find): 查找的是etc目录下的以init为名字的文件. 加通配符后为模糊搜索,只要文件名中含有init即可. 查找etc目录下以init开头的七位文件名. 2.搜索时不区分 ...
- 18-ESP8266 SDK开发基础入门篇--TCP 服务器 RTOS版,串口透传,TCP客户端控制LED
https://www.cnblogs.com/yangfengwu/p/11112015.html 先规定一下协议 aa 55 02 01 F1 4C 控制LED点亮 F1 4C为CRC高位和低位 ...
- 洛谷 P1508 Likecloud-吃、吃、吃 题解
P1508 Likecloud-吃.吃.吃 题目背景 问世间,青春期为何物? 答曰:"甲亢,甲亢,再甲亢:挨饿,挨饿,再挨饿!" 题目描述 正处在某一特定时期之中的李大水牛由于消化 ...
- 验证和交叉验证(Validation & Cross Validation)
之前在<训练集,验证集,测试集(以及为什么要使用验证集?)(Training Set, Validation Set, Test Set)>一文中已经提过对模型进行验证(评估)的几种方式. ...
- SQL基础-子查询&EXISTS&UNION
一.子查询 1.使用子查询作为计算字段 子查询:嵌套在其他查询中的查询 现在有两个表,student表和teacher表 创建teacher表,并插入数据: CREATE TABLE `teacher ...