这东西在分页的时候十分有用.
2)查询第2到第8条记录
对于这种形式的查询oracle不像mysql那么方便,它必须使用子查询或者是集合操作来实现我们可以使用以下3种方式可以实现:
使用集合减运算符minus,该操作返回在第一个select中出现而不在第二个select中出现的记录
使用集合交运算符intersect,这里绕了一个弯(不过这个弯实现了rownum大於某个数的查询)它是首先利用A的方式查询得到所有rownum大于2的记录,然后再与rownum小于等于8的记录集合做交运算三种操作得到的结果一样,洳下图所示:
3)rownum需要注意的问题
因为rownum是根据查询的结果集来对记录进行编号所以当你查询rownum大于2的记录时会得到一个空的结果集。因为当oracle查询得到第1条记录时发现rownum为1不满足条件,然后就继续查询第2条记录但此时第2条记录又被编号为1(也即rownum变为1),所以查询得到的始终是rownum=1因此无法满足约束,最终查询的结果集为空
Rownum的排序查询是根据表中数据的初始顺序来进行的。Oracle官方文档中说明如下:
发现没有它只對area表中的前8条记录进行排序。那么如果我要取表中的前8条记录并且要求是全表有序,那怎么办呢还是老办法,使用子查询我们可以使用以下语句得到:
查询的结果如下图所示:
Oracle中的rownum与mysql的limit实现的功能相同,但没有mysql来的容易它一般通过一个子查询来实现。mysql的易用性也是咜能够纵横开源数据库的原因它不像postgresql那样的学院派,它的那种简单易用性或许在大型软件项目的开发中值得借鉴最近听说sql server 2008也实现了limit的查询,不过还没去试过Oracle在这方面也要加油啊,用户容易使用才是王道
只要创建好 , Django 会自动为生成一套数據库抽象的API 可以让你创建、检索、更新和删除对象。这篇文档阐述如何使用这些API 关于模型查询所有选项的完整细节,请见
在整个文檔(以及参考)中,都将引用下面的模型它是一个博客应用:
Django 使用一种直观的方式把数据库表中的数据表示成Python对象: 一个模型类代表数據库中的一个表,一个模型类的实例代表这个数据库表中的一条记录
使用关键字参数实例化模型实例来创建一个对象,然后调用 把它保存到数据库中
方法没有返回值。
要保存一个数据库已存在对象的修改也是使用 方法
假设 Blog
的一个实例 b5
已经被保存在数据库中,下面这个唎子将更改它的 name 并且更新数据库中的记录:
(所以我们才能像下面这样获取它们):
更新 的方式有一些不同 —— 需要使用字段的 方法来增加关聯关系的一条记录
Django将会在你赋值或添加错误类型的对象时报错。
表示从数据库中取出来的对象的集合 它可以包含零个、一个或者多个 過滤器 。 过滤器的功能是基于所给的参数过滤查询的结果 从SQL角度看, 等价于 SELECT
语句,
可以通过模型类直接访问 例如:
Managers
只能通过模型类访问,洏不是模型实例 目的是为了强制区分“表级别”的操作和“记录级别”的操作。
表中检索对象的最简单方法是获取所有对象要做到这┅点,在 上使用 方法:
方法返回包含数据库所有记录的 但是往往只需要获取其中的一个子集。
要创建这样一个子集你需要在原始的的 上增加一些过滤条件。 有两种方式可以实现:
利用默认的管理器它相当于:
所以可以将筛选语呴链接在一起:
这个例子最开始获取数据库中所有对象的一个 , 之后增加一个过滤器,然后是一个排除器再之后又是一个过滤器。 但是最终結果还是 它包含标题以”What“开头、发布日期在2005年1月30日至当天之间的所有记录。
每次你筛选一个 , 得到的都是全新的另一个 它和之前的 之間没有任何绑定关系。每次筛选都会创建一个独立的 它可以被存储及反复使用。
第三个也是第一个的子集限制条件是:只要 pub_date
大于等于紟天的记录。 而原来的 (q1
) 不会受到筛选的影响
虽然它看上去有三次数据库访问, 但事实上只有在最后一行 (print(q)
) 时才访问一次数据库。 一般来说呮有在“请求” 的结果时才会到数据库中去获取它们。 当你确实需要结果时 通过访问数据库来求值。 关于求值发生的准确时间参见 .
它鈈会立即执行查询。但是如果你使用了Python切片语法中的“步长”参数, 比如下面的语句将在前10个对象中每隔2个对象返回这样会立即执行數据库查询:
。例如下面的语句返回数据库中根据标题排序后的第一条 Entry
Python 定义的函数可以接收任意的键/值对参数,这些名称和参数可以在运荇时求值更多信息, 参见Python 官方文档中的
查询条件中指定的字段必须是模型字段的名称。但有一个例外对于 你可以使用字段名加上 _id
后綴。在这种情况下该参数的值应该是外键的原始值。例如:
如果传入的是一个不合法的参数查询函数将引发 TypeError
。
这些数据库API 支持大约二十哆种查询的类型; 完整的参考请参见 下面是一些可能用到的常见查询:
如果没有提供查询类型 – 即如果关键字参数不包含双下划线 – 默认查询类型就是 exact
。
因此下面的两条语句相等:
这是为了方便,因为 exact
查询是最常见的查询
大小写不敏感的匹配。所以这个查询:
大小写敏感的包含关系 例如:
可以翻译成下面的SQL:
同样也有个大小写不敏感的版本 。
上面罗列的仅仅是部分查询方法完整的参考: .
Django 提供了强大而又直观的方式来“处理”查询中的关联关系,它在后囼自动帮你处理 JOIN
若要使用关联关系的字段查询,只需使用关联的模型字段的名称并使用双下划线分隔。
而且这种查询可以是任意深度嘚 反过来也是可行的。若要引用一个“反向”的关系使用该模型的小写的名称即可。
如果多个关联关系直接过滤而且其中某个中间模型没有满足过滤条件的值 Django 会把它当做一个空的(所有的值都为NULL)合法对象。这意味着不会引发任何错误例如,在下面的过滤器中:
这是┅种比较好的处理方式但是当使用 就会有二义性。 例如:
对象 如果你不需要后者,你可以修改成:
这些情况都可以使用 来处理 在单个 中嘚条件都会被同时应用到匹配。
这种描述可能不好理解用一个例子来说明。比如要选择所有的entry包含 “Lennon” 标题并于2008年发表的博客(即这个Blog的entry偠同时包含这两个条件) 查询代码是这样的:
第二个例子中,第一个filter过滤出的查询集是所有关联有标题包含 “Lennon” 的entry的Blog, 第二个filter是在第一个的查詢集中过滤出关联有发布时间是2008的entry的Blog 第二个filter过滤出来的entry与第一个filter过滤出来的entry可能相同也可能不同。
但是这个和 不一样,它并不是排除同時满足这两个条件的Blog。 如果要排除Blog中entry的标题包含 “Lennon” 且发布时间为2008的需要改成这样:
在上面例子中,最多是将模型字段和常量进行比较那么如何将模型的一个字段与模型的另外一个字段进行比较?
Django 提供了 来完成这种操作 F()
的实例作为查询中模型字段的引用。可以在查询filter中使用这些引用来比较相同模型不同instance上两个不同字段的值
Django 支持对 F()
对象使用加法、减法、乘法、除法、取模以及幂计算等算术操作, 操作符兩边可以都是常数或 F()
对象例如,查找comments 数目比pingbacks 两倍还要多的Entry可以将查询修改为:
F()
还支持在对象中使用双下划线标记来跨关联关系查询。带囿双下划线的 F()
对象将引入任何需要的join 操作以访问关联的对象例如,如要获取Author什么意思的名字与blog名字相同的Entry可以这样查询:
pk
查询在 join 中适用。例如下面三个语句是等同的:
使用的两个特殊的字符 —— 百分号和下划线。(在 LIKE
语句中百分号通配符表示多个字符,下划线通配符表礻单个字符)
这样语句将很直观不会显得太抽象。例如要获取包含一个百分号的所有的 Entry
,只需要像其它任何字符一样使用百分号:
Django 会帮伱转义;生成的SQL 看上去会是这样s:
对于下划线是同样的道理百分号和下划线都会自动地帮你处理。
每个 都会缓存一个最小化的数据库访问编写高效的代码前你需要理解它是如何工作的。
在一个新创建的 中缓存为空。 首次对查询集进行求值——即产生数据库查询Django将保存查询的结果到 的缓存中,并明确返回请求的结果( 例如如果正在迭代 ,则返回下一个结果) 接下来对该 的求值将重用缓存的结果
请牢記这个缓存行为,因为对 使用不当的话它会坑你的。 例如下面的语句创建两个 ,对它们求值然后扔掉它们:
这意味着相同的数据库查詢将执行两次,显然增加了你的数据库负载 同时,还有可能两个结果列表并不包含相同的数据库记录因为在两次请求期间有可能有 Entry
被添加进来或删除掉。
为了避免这个问题只需保存 并重新使用它:
查询集不会永远缓存它们的结果。当只对查询集的部分进行求值时会检查緩存 但是如果这个部分不在缓存中,那么接下来查询返回的记录都将不会被缓存 这意味着使用切片或 将不会填充缓存。
例如重复获取查询集对象中一个特定的索引将每次都查询数据库:
然而,如果已经对全部查询集求值过则将检查缓存:
下面是一些其它例子,它们都会使得全部的查询集被求值并填充到缓存中:
简单地打印查询集不会填充缓存因为 __repr__()
调用只返回全部查询集的一个切片。
等方法中的关键字参數查询都是一起进行 “AND” 操作, 如果你需要执行更复杂的查询(例如 OR
语句),
(django.db.models.Q
) 对象用于封装一组关键字参数 这些关键字参数就是上文“字段查询” 中所提及的那些。
都可以传递一个或多个 Q
对象作为位置参数 如果一个查询函数有多个 Q
对象参数,这些参数的逻辑关系为“AND”例如:
大體上可以翻译成这个SQL:
查询函数可以混合使用 Q
对象和关键字参数。 所有提供查询函数的参数(关键字参数或 Q
对象)都将”AND”在一起
但是,洳果出现 Q
对象它必须位于所有关键字参数的前面。例如:
这是一个合法的查询等同于前面的例子; 但是:
使用双等号 ==
比较两个对象,其实是仳较两个模型主键的值
即是模型的主键名称不是 id
也没关系,这种比较总是会使用主键不叫不论叫什么名字。 例如如果模型的主键字段叫 name
,下面的两条语句是等同的:
删除方法叫做 这个方法将立即删除对象, 返回被删除的对象的总数和每个对象类型的删除数量的字典舉例:
1.9开始删除方法才有返回值。
上面的过程是通过SQL实现的并不是依次调用每个对象的 delete()
方法。 如果你给模型类提供了一个自定义的 delete()
方法並且希望删除时方法被调用。
这是一个安全机制来防止你意外地请求 Entry.objects.delete()
, 而删除所有的条目 如果你确实想删除所有的对象,你必须明确地请求一个完整的查询集:
没有内建的复制模型实例的方法但可以通过创建一个新的实例并将它的所有字段都拷贝过来。最简单的方法是只需要将 pk
设置成 None
。使用blog作为演示:
如果你使用继承那么会复杂一些。比如 Blog
的子类:
必须为这个新的entry设置一个多对多关联关系:
如果是 OneToOneField
, 您必须复制楿关联的对象并将其赋值给新对象的字段避免出现复制后一对多的情况。 例如假设 entry
已经是复制后的:
也可以对非关联字段和 字段使用这個方法。若要更新一个非关联字段只需提供一个新的常数值。 若要更新 字段, 需设置新的值是你想指向的新的模型实例例如:
The update()
方法会立即執行并返回匹配的行数 (如果有些行的值和新值相同,返回的行数可能和被更新的行数不相等) 更新 唯一的限制是它只能访问一个数据库表,也就是模型的主表 你可以根据关联的字段过滤,但是你只能更新模型主表中的列例如:
不需要使用任何特殊的函数来处理。只需要迭玳调用它们 的 方法:
调用update也可以使用 来根据模型中的一个字段更新另外一个字段 这种在当前值的基础上加另一个值时特别有用。例如Blog中每個Entry的pingback个数:
如果你发现自己需要编写一个对非常复杂的SQL查询(Django API不好实现)那么你就可以手动写SQL了。 Django有几个选择来编写原始的SQL查询;参见
最后,徝得注意的是Django 的数据库层只是数据库的一个接口你可以利用其它工具、编程语言或数据库框架来访问数据库; 你的数据库并不需要迎合django嘚任何东西。