Django数据库查询相关

zz/2024/7/17 21:30:17

一旦数据模型创建完毕,自然会有存取数据的需要.

本文档介绍了由models衍生而来的数据库抽象API,及如何创建,得到及更新对象.

贯穿本参考, 我们都会引用下面的民意测验(Poll)应用程序:

class Poll(models.Model):
   slug = models.SlugField(unique_for_month='pub_date')
   question = models.CharField(maxlength=255)
   pub_date = models.DateTimeField()
   expire_date = models.DateTimeField()
  def __repr__(self): 
    return self.question
class Meta:
   get_latest_by = 'pub_date'
class Choice(models.Model):
   poll = models.ForeignKey(Poll, edit_inline=models.TABULAR,
num_in_admin=10, min_num_in_admin=5)
   choice = models.CharField(maxlength=255, core=True)
   votes = models.IntegerField(editable=False, default=0) 
def __repr__(self):
   return self.choice

及下面的简单会话:

>>> from datetime import datetime 
>>> p1 = Poll(slug='whatsup', question="What's up?",
... pub_date=datetime(2005, 2, 20), expire_date=datetime(2005, 4, 20)) 
>>> p1.save()
>>> p2 = Poll(slug='name', question="What's your name?",
... pub_date=datetime(2005, 3, 20), expire_date=datetime(2005, 3, 25)) 
>>> p2.save() 
>>> Poll.objects.all()
[What's up?, What's your name?]
 
 

查询如何运作

Django 的数据查询基于构建结果集及对结果集进行取值. 结果集是独立于数据库的符合某个查询条件的一组数据对象的集合.这是一个惰性集合:在对该集合取值之前,无法知道该集合有哪些成员.

要生成一个满足你需求的结果集,首先要得到一个描述给定类型的所有对象的初始结果集.这个初始结果集可以通过一系列函数进行更精细的优化处理.当经 过处理后的结果集符合你的要求时, 就可以对它进行取值操作(使用迭代操作,slicing操作,或一系列其它技术), 以得到一个你需要的对象或对象的列表.

 

获得初始结果集

每个 Django model 都有一个与生俱来的管理器对象 objects, 管理器最重要的角色就是作为初始结果的来源. 一个管理器就是一个描述给定类型所有对象的特殊的初始结果集. Poll.objects 就是包含所有 Poll 对象的一个初始结果集. 它唯一特殊之处在于它不能被取值. 要克服此限制, 管理器对象有一个 all() 方法. 该方法生成一个 可以 被取值的初始结果集的拷贝:

all_polls = Poll.objects.all()

参阅 Model API 的 Managers 小节以了解管理器的定位及创建细节.

 

优化定制结果集

管理器提供的初始结果集描述了给定类型的所有对象.不过通常你只需要这个对象集合中的一小部分(一个子集).

要生这样一个结果集,你需要对初始结果集进行优化定制处理, 增加一些限制条件直到描述的子集满足你的需要.最常用的两个定制结果集的方法是:

filter(**kwargs)

返回一个匹配查询参数的新的结果集.

exclude(**kwargs)

返回一个不匹配查询参数的新的结果集.

参数格式在下面 "字段查询" 小节有描述.

这两个方法的返回值都是结果集对象,因此结果集可以进行链式处理:

Poll.objects.filter(question__startswith="What").exclude(
pub_date__gte=datetime.now()).
filter(pub_date__gte=datetime(2005,1,1))

...以一个初始结果集作为参数, 然后进行过滤, 再进行排除, 再进行另一个过滤. 这样得到的最终结果就一个问题开头单词是 "What", 发布日期在 2005年1月1日至今的所有民意测验的集合.

每个结果集都是一个独一无二的对象. 以上操作的每一步都生成了一个新的结果集:

q1 = Poll.objects.filter(question__startswith="What") 
q2 = q1.exclude(pub_date__gte=datetime.now()) 
q3 = q1.filter(pub_date__gte=datetime.now())

这三步生成了三个结果集; 一个初始结果集包含所有的以"What"开头的民意测验, 两个初始结果集的子集(一个排除条件,一个过滤条件).对原始结果集的改进过程并没有影响到原始的结果集.

值得注意的是结果集的创建根本没有访问数据库.只有当对结果集取值时才会访问数据库.

字段查询

以 field__lookuptype (注意是双下线)形式进行基本的字段查询,举例来说:

polls.objects.filter(pub_date__lte=datetime.now())

该查询翻译成SQL就是:

SELECT * FROM polls_polls WHERE pub_date <= NOW();

实现细节

Python 能够在定义函数时接受任意的 name-value(names和values均可以在运行时通过计算得到)参数. 要了解更多信息,参阅官方 Python 教程中的 关键字参数 .

DB API 支持下列查找类型:

类型描述
exact精确匹配: polls.get_object(id__exact=14).
iexact忽略大小写的精确匹配: polls.objects.filter(slug__iexact="foo") 匹配 foo, FOO, fOo, 等等.
contains大小写敏感的内容包含测试: polls.objects.filter(question__contains="spam") 返回question 中包含 "spam" 的所有民意测验.(仅PostgreSQL 和 MySQL支持. SQLite 的LIKE 语句不支持大小写敏感特性. 对Sqlite 来说, contains 等于 icontains.)
icontains大小写不敏感的内容包含测试:
gt大于: polls.objects.filter(id__gt=4).
gte大于等于.
lt小于.
lte小于等于.
ne不等于.
in位于给定列表中: polls.objects.filter(id__in=[1, 3, 4]) 返回一个 polls 列表(ID 值分别是 1或3或4).
startswith大小写敏感的 starts-with: polls.objects.filter(question__startswith="Would").(仅PostgreSQL 和MySQL支持. SQLite 的LIKE 语句不支持大小写敏感特性. 对Sqlite 来说,``startswith`` 等于 istartswith)
endswith大小写敏感的 ends-with. (仅PostgreSQL 和 MySQL)
istartswith大小写不敏感的 starts-with.
iendswith大小写不敏感的 ends-with.
range范围测试: polls.objects.filter(pub_date__range=(start_date, end_date)) 返回 pub_date 位于 start_date 和 end_date (包括)之间的所有民意测验
year对 date/datetime 字段, 进行精确的  匹配: polls.get_count(pub_date__year=2005).
month对 date/datetime 字段, 进行精确的  匹配:
day对 date/datetime 字段, 进行精确的  匹配:
isnullTrue/False; 做 IF NULL/IF NOT NULL 查询:polls.objects.filter(expire_date__isnull=True).

 

如果未提供查找类型, 系统就认为查找类型是 exact . 下面两个语句是等价的:

Poll.objects.get(id=14)
Poll.objects.get(id__exact=14)

查询允许多个条件参数, 逗号分隔的多个条件参数会被 "AND" 起来使用:

polls.objects.filter(pub_date__year=2005,
pub_date__month=1,
question__startswith="Would" )

...得到2005年1月公布的带有一个"Would"开头的问题的所有民意测验.

 

为了使用更加方便, 还提供有一个 pk 查找类型, 可以翻译成 (primary_key)__exact. 在这个民意测试的例子里, 下面两个语句是等价的.:

polls.get_object(id__exact=3) 
polls.get_object(pk=3)

pk 也可以通过连接进行查询. 在这个民意测试的例子里, 下面两个语句是等价的:

choices.objects.filter(poll__id__exact=3) 
choices.objects.filter(poll__pk=3)

如果传递的关键字参数非法, 将引发 TypeError 异常.

 

OR 查询

关键字参数查询的各个条件都是 "AND" 关系. 如果你需要一个复杂的查询(举例来说,你需要一个 OR 语句), 你需要使用 Q 对象.

Q 对象是 django.core.meta.Q 的实例, 用来装载一系列关键字参数. 

这些关键字参数就象指定给 get() 和 filter() 函数的关键字参数一样. 举例来说:

Q(question__startswith='What')

Q 对象可以使用 & 和 | 运算符进行组合. 当两个Q对象进行 & 或 | 运算时,会生成一个新的Q对象.

举例来说语句:

Q(question__startswith='Who') | Q(question__startswith='What')

... 生成一个新的 Q 对象表示这两个 "question__startswith" 查询条件的 "OR" 关系. 

等同于下面的 SQL WHERE 子句:

... WHERE question LIKE 'Who%' OR question LIKE 'What%'
 

通过对多个 Q 对象的 & 和 | 运算你能得到任意复杂的查询语句. 也可以使用圆括号分组.

查询函数可以接受一个或多个 Q 对象作为参数.如果提供有多个 Q 对象参数, 它们将被 "AND" 到一起. 举例来说:

polls.get_object( 
Q(question__startswith='Who'), 
Q(pub_date__exact=date(2005, 5, 2)) | 
Q(pub_date__exact=date(2005, 5, 6)) 
)

... 翻译成 SQL 就是这样:

SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
 

如果需要,查询函数可以混合使用 Q 对象参数和关键字参数. 所有提供给查询函数的参数(不管是关键字参数还是Q对象)都被 "AND" 到一起. 如果提供了 Q 对象作为参数,它就必须在其它关键字参数(如果有的话)的前面. 举例来说:

polls.get_object( 
Q(pub_date__exact=date(2005, 5, 2)) | Q(pub_date__exact=date(2005, 5, 6)),
question__startswith='Who')

... 这是一个合法的查询, 等价于前一个例子,不过:

# INVALID QUERY
polls.get_object(
question__startswith='Who',
Q(pub_date__exact=date(2005, 5, 2)) | Q(pub_date__exact=date(2005, 5, 6)))

... 这个查询则不符合我们的规则,会引发异常.

Q 对象也可以以 complex 关键字参数的形式使用. 

举例来说:

polls.get_object(
complex=Q(question__startswith='Who') &
(Q(pub_date__exact=date(2005, 5, 2)) | 
Q(pub_date__exact=date(2005, 5, 6))
) 
)

参阅 OR 查询示例 以实例.

 

从结果集中取值

只有通过取值操作才能得到结果集包含的对象.取值操作可以通过迭代,切片,或其它专门的函数来实现.

一个结果集就是一个可迭代对象.因此,可以通过一个循环来取出它的值:

for p in Poll.objects.all(): 
  print p
 

将使用 Poll 对象的 __repr__() 方法打印出所有的 Poll 对象.

一个结果集也可以被切片, 使用数组符号操作:

fifth_poll = Poll.objects.all()[4] 
all_polls_but_the_first_two = Poll.objects.all()[2:]
every_second_poll = Poll.objects.all()[::2]
 

结果集对象是惰性对象 - 也就是说,他们不是 真正的 包含他们表示对象的集合 (或列表). 

Python 的协议魔法让结果集看起来是一个可迭代,可切片的对象. 

事实上在幕后, Django 使用了缓存技术,如果你真的需要一个列表, 你可以强制对一个惰性对象取值:

querylist = list(Poll.objects.all())

不过,最好不要这么做,尤其当一个结果集相当大时. 由于 Django 要创建每一个对象的内存表示,这将占用相当大的内存.

 

结果集及其缓存行为

每个结果集都包含一个 cache. 对一个新创建的结果集来说, 缓存区是空的.当一个结果集第一次被取值, Django 会进行一次数据库查询,并将查询结果放入缓存中, 之后返回用户需要的数据. 后面的取值操作会使用缓存中的数据而不用再次访问数据库.

必须时刻记住:结果集具有缓存行为. 下面两行语句生成了两个临时的结果集,并进行了取值,之后舍弃:

print [p for p in Poll.objects.all()] # Evaluate the Query Set 
print [p for p in Poll.objects.all()] # Evaluate the Query Set again
 

对一个小型的,低流量的站点来说,这不会造成严重问题.不过,对一个高访问量的站点来说,它双倍增加了数据库服务器的负担.另外,由于在两次操作之间可能有其它的用户增加或删除了投票,因此这两次操作得到结果可能并不相同.

要避免这个问题, 保存这个结果集并在后面重用该结果集:

queryset = Poll.objects.all()
print [p for p in queryset] # Evaluate the query set 
print [p for p in queryset] # Re-use the cache from the evaluation
 
 

 

 

 

 

update()方法会返回一个整型数值,表示受影响的记录条数。 在上面的例子中,这个值是2。 删除对象

删除数据库中的对象只需调用该对象的delete()方法即可:

?

1

2

3

4

>>> p = Publisher.objects.get(name="O'Reilly")

>>> p.delete()

>>> Publisher.objects.all()

[<Publisher: Apress Publishing>]

同样我们可以在结果集上调用delete()方法同时删除多条记录。这一点与我们上一小节提到的update()方法相似:

?

1

2

3

4

>>> Publisher.objects.filter(country='USA').delete()

>>> Publisher.objects.all().delete()

>>> Publisher.objects.all()

[]

删除数据时要谨慎! 为了预防误删除掉某一个表内的所有数据,Django要求在删除表内所有数据时显示使用all()。 比如,下面的操作将会出错:

?

1

2

3

4

>>> Publisher.objects.delete()

Traceback (most recent call last):

 File "<console>", line 1, in <module>

AttributeError: 'Manager' object has no attribute 'delete'

而一旦使用all()方法,所有数据将会被删除:

?

1

>>> Publisher.objects.all().delete()

如果只需要删除部分的数据,就不需要调用all()方法。再看一下之前的例子:

?

1

>>> Publisher.objects.filter(country='USA').delete()

 
 
 

数据更新

 

Python代码

  1. >>> Publisher.objects.filter(id=52).update(name='Apress Publishing')  

[python] view plain copy

  1. >>> Publisher.objects.filter(id=52).update(name='Apress Publishing')  
  2.  

http://www.ngui.cc/zz/2762640.html

相关文章

js中return、return true、return false的区别

一、返回控制与函数结果&#xff0c; 语法为&#xff1a;return 表达式;语句结束函数执行&#xff0c;返回调用函数&#xff0c;而且把表达式的值作为函数的结果。 二、返回控制&#xff0c;无函数结果&#xff0c;语法为&#xff1a;return;在大多数情况下,为事件处理函数返回…

django的session保存策略(时间)

session的超时时间设置settings中 SESSION_COOKIE_AGE60*30 30分钟。 SESSION_EXPIRE_AT_BROWSER_CLOSEFalse&#xff1a;会话cookie可以在用户浏览器中保持有效期。True&#xff1a;关闭浏览器&#xff0c;则Cookie失效。 SESSION_COOKIE_DOMAIN 生效站点SESSION_COOKI…

HTML5线性图表iGrapher 功能非常强大

原文&#xff1a;http://www.html5tricks.com/html5-chart-igrapher.html 各种图标的绘制&#xff0c;Hightchart &#xff1a;http://www.hcharts.cn/

轻量级图形报表工具JSCharts (JSChart),内置函数中文参考(二)

1. 实例化 JSCharts var mychartsnew JSCharts(“ chartId”,”bar ” ); 注&#xff1a;chartId-<div>标签的id、bar-图的类型 如&#xff08;饼图、线图 等。。。&#xff09;。 2.JSCharts 设置数据。 var myData new Array([10, 20], [15, 10], [20, 30], [25, 1…

Shell重定向 &file、21、12 、/dev/null的区别

在shell脚本中&#xff0c;默认情况下&#xff0c;总是有三个文件处于打开状态&#xff0c;标准输入(键盘输入)、标准输出&#xff08;输出到屏幕&#xff09;、标准错误&#xff08;也是输出到屏幕&#xff09;&#xff0c;它们分别对应的文件描述符是0&#xff0c;1&#xff…

【深度学习】RNN(循环神经网络)

1 循环神经网络&#xff08;RNN&#xff09;概念 循环神经网络&#xff0c;是一种线性序列结构&#xff0c;前一个神经元的结果会传递给后一个神经元。 递归神经网络&#xff0c;是一种层次结构&#xff0c;前一个神经元会影响后一个神经元&#xff0c;后一个神经元同样也会影…

wget因为https和ssl的原因不能下载

在使用wget下载过程中&#xff0c;有时会因为https和ssl的原因&#xff0c;出现类似"Unable to establish SSl connection"的错误&#xff0c;导致不能下载。这时可以使用 --no-cookie --no-check-certificate 这两个参数解决。 wget --no-cookie --no-check-certi…

jps 、jstack命令详解

一、jps命令shi yong jps是jdk提供的一个查看当前java进程的小工具&#xff0c; 可以看做是JavaVirtual Machine Process Status Tool的缩写。非常简单实用。 命令格式&#xff1a;jps [options ] [ hostid ] [options]选项 &#xff1a; -q&#xff1a;仅输出VM标…

推荐算法--基于用户的协同过滤算法

基于邻域的算法分为两大类&#xff0c;一类是基于用户的协同过滤算法&#xff0c;另一类是基于物品的协同过滤算法。 我们先来看看基于用户的协同过滤算法&#xff0c;基于物品的协同过滤算法大体思路和基于用户的差不多&#xff0c;可以自己参考对比学习。 基于用户的协同过…

sklearn机器学习算法速查

常见的机器学习算法 以下是最常用的机器学习算法&#xff0c;大部分数据问题都可以通过它们解决&#xff1a; 线性回归 (Linear Regression)逻辑回归 (Logistic Regression)决策树 (Decision Tree)支持向量机&#xff08;SVM&#xff09;朴素贝叶斯 (Naive Bayes)K邻近算法&a…