django学习之Model(四)MakingQuery
上一篇写到MakingQuey中的filter,本篇接着来。
10)-扩展多值的关系
如果对一个ManyToManyField或ForeignKey的表进行filter过滤查询的话,有2中方法可以用。分别是:
#
Blog.objects.filter(entry__headline__contains='Lennon',
entry__pub_date__year=2008) #
Blog.objects.filter(entry__headline__contains='Lennon').filter(
entry__pub_date__year=2008)
假设,现有一个blog表,它对应了很多的entry的表,而且这个blog既有含有“Lennon”的entry,也有含有2008的entry,但是没有那种2者都有的entry,那么第一个方法过滤的是2者都有的entry,所以没有符合条件的blog返回。第一种方法可以理解为“并且”的意思。第二种是第一个filter返回含有“Lennon”的blog,然后在这个blog集合中,再选有2008的,所以会有blog返回。开始理解起来很费劲,抓住特点:一个blog对应多个entry。例如,blog1对应了entry1,entry2,entry3,其中entry1只有“Lennon”,没有2008;entry2只有2008,没有“Lennon”;entry3则什么都没有。那么用第一种方法来filter的时候,则没有满足既有Lennon又有2008的entry;第二种方法的第一个filter,因为entry1有Lennon,所以blog1为返回值,然后对返回值blog1进行filter,条件为有2008,而blog1中的entry2是有2008的,所以blog1作为返回值。
这个也适用于exlude().
11)-filters可以引用model中的fields
class F
目前为止的例子中,都是用field中的值来作为filter的条件来进行数据查询。但是如果需要把一个field的值与他所在的model的其他field的值呢?
django提供F()表达式来实现这种比较。F()的实例是在一个query中来对model中的field进行引用。这些引用可以作为filter的条件来进行过滤。
例如,要查询blog的entry,comments满足的数量比pingbacks的多,可以用F()来作用在pingbacks上,然后把结果作为filter的条件:
>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
注意:F()表达式中是n_comments比大n_pingbacks。所以,也有倍数、加、减这样的操作可以来比较:
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)#
n_comments比n_pingbacks的2倍多 >>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))#n_comments与n_pingbacks的和比rating多
gt是多理解为>,lt理解为<.
而下面的例子则是两个字符串一样:
>>> Entry.objects.filter(authors__name=F('blog__name'))
12)-pk
是primary key的意思:
>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14) # __exact is implied
>>> Blog.objects.get(pk=14) # pk implies id__exact
# Get blogs entries with id 1, 4 and 7
>>> Blog.objects.filter(pk__in=[1,4,7]) # Get all blog entries with id > 14
>>> Blog.objects.filter(pk__gt=14)
同样应该有这些符号的组合,分别是__双下划线,lt,gt,exact等等。
如果查询含有%符号的,下例给出:
>>> Entry.objects.filter(headline__contains='%')
同样的_下划线符号也是,django会自动来处理的,就像上边这行程序这样写就行了。
5-QuerySet的缓存
每个QuerySet都有缓存来降低对数据库database的访问。弄明白了之后,可以写出高效率的代码。
在新创建的QuerySet中,缓存是空的。当QuerySet第一次 被计算的时候,django把QuerySet放在其缓存中,然后把具体要查询的数据项作为结果返回。把QuerySet这种缓存的行为时刻记住,有的时候很容易使用不当的。例如下面,建立了2个QuerySet,分别使用后,就丢掉了,这样造成了2次访问database,而且第二个e很可能不是第一个e,因为在第二个发生之前,database很可能已经被写入新数据或删除什么东西了:
>>> print([e.headline for e in Entry.objects.all()])
>>> print([e.pub_date for e in Entry.objects.all()])
正确的做法如下,建立个变量来存放QuerySet,让它一直放在内存中,然后每次用的时候从内存中去读取:
>>> queryset = Entry.objects.all()
>>> print([p.headline for p in queryset]) # Evaluate the query set.
>>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.
注意,第一行并没有touch the database,访问数据库发生在第二行代码。
QuerySet也并不是总缓存结果的,当计算queryset的一部分的时候,要缓存,但是如果只是用一个下一层的queryset来访问结果的时候,并没有缓存。这也意味着,可以用数组分片或者一个索引来限制queryset而不产生缓存,例如下面的例子,显示只定义了一个queryset来存放objects,然后用数组来访问其中的某一个,这样就没有缓存,每次都要重新访问数据库:
>>> queryset = Entry.objects.all()
>>> print queryset[5] # Queries the database
>>> print queryset[5] # Queries the database again
然而,如果整个queryset都被计算了,那么就会产生缓存:
>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # Queries the database
>>> print queryset[5] # Uses cache
>>> print queryset[5] # Uses cache
还有一些例子也是整个querset都被计算了,当然产生了缓存:
>>> [entry for entry in queryset]
>>> bool(queryset)
>>> entry in queryset
>>> list(queryset)
6-用Q对象来进行复杂的查询
在filter()方法中,用关键字来查询,这些关键字是AND的关系,即”并且“,如果需要进行更复杂的查询,例如OR关系,可以用Q对象这种方法。
Q对象(django.db.models.Q)是用来封装关键字的集合的。这些关键字包括上文的lookup查询中所提到的关键字。例如,下面这个Q对象封装了LIKE查询:
from django.db.models import Q
Q(question__startswith='What')
Q对象可以用逻辑符号&或者|来连接,结果返回一个Q对象:
Q(question__startswith='Who') | Q(question__startswith='What')
同等于SQL语句:
WHERE question LIKE 'Who%' OR question LIKE 'What%'
可以把Q对象组合成复杂的表达,也可以用~符号,代表”NOT,非“的意思:
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
每个查询函数(filter(), get(), exclude())都需要有关键字,Q对象就可以作为这些查询函数的关键字:
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
翻译成SQL语句就相当痛苦了:
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
查询函数也可以混合使用keywords和Q object,但是要注意,Q object必须在keyword之前定义:
#正确的
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who')
#错误的
Poll.objects.get(
question__startswith='Who',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
7-比较对象
用python标准的比较操作符==就可以进行model实例的比较。而这实际上实在比较primarykey的值:
>>> some_entry == other_entry
>>> some_entry.id == other_entry.id#实际上
如果model的primarykey不叫id,没关系,照样还是在比较primarykey,例如一个model的primarykey是name,则下面2行代码是同样意思的:
>>> some_obj == other_obj
>>> some_obj.name == other_obj.name
8-删除对象
delete()用来进行对象的删除,而且是立即生效,并且没有返回值:
e.delete()
也可以批量来进行删除操作,每个QuerySet都有delete()操作,可以把QuerySet中的所有对象都删掉:
Entry.objects.filter(pub_date__year=2005).delete()
delete是Manager的一个方法,但是由于怕用户误操作而没有显式的显现出来。因为delete是纯粹的在SQL中执行的方法,所以不需要用户在过程中去认为的调用。如果你在一个model的class定义中自己定义了一个delete()的话,那么就相当于覆盖掉了Manager提供的delete,这样就需要用户自己去调用了,而且这种自己定义的delete()还不能批量的来操作,也就是不能作为QuerySet中的参数来调用,而是需要自己对每个object单独进行delete一次。
django提供的delete()方法,会删除由foreignkey来关联到一起的object:
b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()
这种串联的用法是通过 on_delete 参数传递给Foreignkey的。
delete是Manager的一个方法,为了防止用户误操作,所以不用显式调用,但是如果确实需要调用delete()来删除所有的objects的话,应该明确的指出来这个QuerySet:
Entry.objects.all().delete()
9-复制model实例
尽管没有built-in的方法来实现model 实例的复制,但是可以用model的所有的fields的值来创建一个新的实例,最简单的情况就是,先把pk设置成None,然后再save:
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1 blog.pk = None
blog.save() # blog.pk == 2
思考:也就是,第1行代码只是把Blog内容放在了blog这个变量中,并没写进去数据库,只有调用save()方法时,才发生写的操作。而且每当调用save(),都相当于要把这个数据(blog)写进数据库。而数据库的pk是唯一而不能重复的,所有先要把blog.pk设成None,然后再操作,由SQL语句把pk由依次递增为2了。
如果有model的继承时,会略复杂一些:
class ThemeBlog(Blog):
theme = models.CharField(max_length=200) django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python')
django_blog.save() # django_blog.pk == 3
因为继承的工作原理,这次需要把pk和id都设成None了:
django_blog.pk = None
django_blog.id = None
django_blog.save() # django_blog.pk == 4
这个过程并没有复制相关联的objects,如果想要复制这种关系,需要多写一些代码了。在本文的例子中,Entry和Author是多对多的关系(ManyToManyField):
entry = Entry.objects.all()[0] # some previous entry
old_authors = entry.authors.all()
entry.pk = None
entry.save()
entry.authors = old_authors # saves new many2many relations
今天到这,明天继续!
django学习之Model(四)MakingQuery的更多相关文章
- django学习之Model(二)
继续(一)的内容: 1-跨文件的Models 在文件头部import进来,然后用ForeignKey关联上: from django.db import models from geography.m ...
- django学习之Model(一)
认认真真学Django,从现在开始. 学习资料来源于官方网站:https://docs.djangoproject.com/en/1.6/ 1-新建一个models.py from django.db ...
- Django 学习笔记(四)模板变量
关于Django模板变量官方网址:https://docs.djangoproject.com/en/1.11/ref/templates/builtins/ 1.传入普通变量 在hello/Hell ...
- django学习之Model(五)MakingQuery
接着上篇. 10-一次更新多个对象 有时想要对QuerySet中的所有对象的某一个field来设定一个值,这时候可以像下边这样用update(): # Update all the headlines ...
- django学习之Model(三)QuerySet
接下来主要学习Models中的Making queries 写好models.py后,django会自动提供一个数据库的抽象API,来实现CRUD(create, retrieve, update, ...
- django 学习之model操作(想细化)
一.Field选项 null=True 数据库为空 blank=True admin相关为空 choices:choices意味着静态数据的变化不会太大. db_column: 用于此字段的数据库的列 ...
- 07.Django学习之model进阶
一 QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. >>> Entry.objects.all( ...
- Django学习之model进阶
一 QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. >>> Entry.objects.al ...
- Django学习笔记〇四——数据库ORM的使用(有待修改)
Django框架基本上都是要和数据库结合使用的,我在以前讲过SQLAlchemy框架的使用,Django支持的不是SQLAlchemy,但是也内嵌了ORM框架,可以不需要直接面对数据库编程,而可以通过 ...
随机推荐
- python的内置函数bin()
bin(x) 中文说明:将整数x转换为二进制字符串,如果x不为Python中int类型,x必须包含方法__index__()并且返回值为integer: 参数x:整数或者包含__index__()方法 ...
- jmeter cookie管理器 使用方法---新手学习记录1
首先得抓包: 我已post方法为例: POST /api/datasources/lemontest/jaql HTTP/1.1 Host: 192.168.1.107:8081 Content-Le ...
- 帝国cms灵动标签下常用标签
这里简单整理下灵动标签下的常用标签 标题名称:<?=$bqr['title']?> <?=esub($bqr[title],22)?> 限制字符22个 标题链接:<?= ...
- 如何禁止scrollView 的子控件自动滑到 底部或者中间部分
现象:当一个scrollView 里面包含很多childView,并且整个界面超出屏幕的范围,而且每个childView都获取焦点,scrollView就会自动滑到底部或者中间部分. 可以使用以下几种 ...
- Flex 全屏显示方法
1,修改html-template下的index.template.html文件…增加四行 1</html> 上述文件增加了四行…见我文中有提示 2,Mxml文件: 假如一个button按 ...
- 拿出来分享了!VIP珍藏!!!全网最齐全的 DEDECMS模板 全盘下载地址列表!没有你找不到的!
拿出来分享了!VIP珍藏!!!全网最齐全的 DEDECMS模板 网盘地址!没有你找不到的! 模板类型最齐全: ----------------------优美的走起!------------ 一:DE ...
- TCP传输连接建立与释放详解
一直以来有许多读者朋友对TCP的传输连接建立和释放过程不是很理解,而这又是几乎网络认证中必考的知识点,包括软考.CCNA\CCNP.H3CNA\H3CNE等,为此再把笔者年度巨作,广受好评的——< ...
- git从github下载代码
Github作为远程仓库的使用详解 http://blog.csdn.net/djl4104804/article/details/50778717 centos local: 通过g ...
- uoj #2 【NOI2014】起床困难综合症 贪心+位运算
题目链接 给出n个数, 每个数有特定的一种操作, &|^三种, 给出一个m, 初始值属于[0,m],选定一个初始值, 使所有操作做完之后的值最大, 输出这个最大值. 1, 从最高位贪心, 如果 ...
- 【转】C++常见错误大全
原文转自:http://hi.baidu.com/qiou2719/item/b9eed949130ff50ec0161331 C++常见错误大全 0. XXXX "is not a cla ...