django学习之Model(三)QuerySet
接下来主要学习Models中的Making queries
写好models.py后,django会自动提供一个数据库的抽象API,来实现CRUD(create, retrieve, update, delete)。这一部分主要就是怎样去用这些API。在data model reference会有全部的讲解。
接下来都会反复用到下边这个例子,或者在这段代码上进行扩展:
- from django.db import models
- class Blog(models.Model):
- name = models.CharField(max_length=100)
- tagline = models.TextField()
- # On Python 3: def __str__(self):
- def __unicode__(self):
- return self.name
- class Author(models.Model):
- name = models.CharField(max_length=50)
- email = models.EmailField()
- # On Python 3: def __str__(self):
- def __unicode__(self):
- return self.name
- class Entry(models.Model):
- blog = models.ForeignKey(Blog)
- headline = models.CharField(max_length=255)
- body_text = models.TextField()
- pub_date = models.DateField()
- mod_date = models.DateField()
- authors = models.ManyToManyField(Author)
- n_comments = models.IntegerField()
- n_pingbacks = models.IntegerField()
- rating = models.IntegerField()
- # On Python 3: def __str__(self):
- def __unicode__(self):
- return self.headline
1-创建对象
一个model class 对应生成一个database table,一个class的实例就对应存进database table中的一个记录。class中的field对应这table中的column.
调用python语法中的怎样给类的对象赋值的语法,然后在调用对象的.save()函数,就创建了一条数据。
假设mysite/blog/models.py,下例:
- >>> from blog.models import Blog
- >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
- >>> b.save()
python语法中的赋值对应SQL的INSERT语句,只有调用save()的时候,django才对database进行了操作。并且save()没有返回值。如果把create和save用一条语句实现,create()方法可以实现。
2-保存对数据的修改
也是用save()实现。即重新赋值,重新save:
- >>> b5.name = 'New name'
- >>> b5.save()
这相当于SQL中的UPDATE, save()
3-保存ForeignKey和ManyToManyField 的fields
update ForeignKey和update普通field是一样的操作,从python角度来讲,就是把一个object赋值给另一个类中的object类型的变量。
- blog = models.ForeignKey(Blog)#相当于blog是一个存放Blog的实例(对象)的一个变量。
但是在update ManyToManyField的时候,用的是add()方法,且不用save()
- >>> from blog.models import Author
- >>> joe = Author.objects.create(name="Joe")
- >>> entry.authors.add(joe)
也可一进行批量操作:
- >>> john = Author.objects.create(name="John")
- >>> paul = Author.objects.create(name="Paul")
- >>> george = Author.objects.create(name="George")
- >>> ringo = Author.objects.create(name="Ringo")
- >>> entry.authors.add(john, paul, george, ringo)
注意类型要匹配,不能把author add到blog中,这样django会报错。
4-检索对象(Retrieving objects)
通过Manager来在model class上建立QuerySet (查询)。QuerySet展示出database中的数据。filters可有可无,filters顾名思义,就是用来过滤,或者说筛选。在SQL中,QuerySet相当于SELECT语句,filters相当于WHERE或LIMIT。可以从model的Manager中获得QuerySet,每个model都有一个Manager,默认使用的是objects.默认的是通过model class来实现,注意下面的代码:
- >>> Blog.objects
- <django.db.models.manager.Manager object at ...>
- >>> b = Blog(name='Foo', tagline='Bar')
- >>> b.objects
- Traceback:
- ...
- AttributeError: "Manager isn't accessible via Blog instances."
用的是Blog.objects, 而不是通常感觉上的对象的方法,因为manager是class的,而不是object的。官方文档说,这种Manager的设计,加强了table-level与record-level操作的分离。可以理解为,整个django更好的实现了起框架的作用,就是不管具体的instance是啥样的,而只注意在框架的设计上,让其普遍适用于各种instance.
1)-最简单的检索database table的对象的方法,就是all,全检索。在Manager上用all():
- >>> all_entries = Entry.objects.all()
all()方法返回了一个QuerySet,包含database中所有的数据对象。
2)-稍微复杂点的就是加上filters来过滤出想要的结果。
常用的有2种:
a)-filter(**kwargs) 返回值为满足参数所表达的条件的QuerySet
b)-exclude(**kwargs) 返回值QuerySet剔除了(exclude)参数所表达的条件的数据。
分别有如下2例:
- Entry.objects.filter(pub_date__year=2006)#年代为2006年的被返回
- Entry.objects.all().filter(pub_date__year=2006)#剔除2006年的,其他剩下的被返回
3)-链式filters
相当于级联式的,看代码就明白了:
- >>> Entry.objects.filter(
- ... headline__startswith='What'
- ... ).exclude(
- ... pub_date__gte=datetime.date.today()
- ... ).filter(
- ... pub_date__gte=datetime(2005, 1, 30)
- ... )
4)-filter后的QuerySet是唯一且不变的
下面代码中的q1,q2,q3是独立互不影响的:
- >>> q1 = Entry.objects.filter(headline__startswith="What")
- >>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
- >>> q3 = q1.filter(pub_date__gte=datetime.date.today())
5)-QuerySet很懒
直到你确实要用到值的时候,QuerySet才去database读取数据,下面代码中就是在print(q)的时候才读database的:(具体解释见When QuerySets are evaluated)
- >>> q = Entry.objects.filter(headline__startswith="What")
- >>> q = q.filter(pub_date__lte=datetime.date.today())
- >>> q = q.exclude(body_text__icontains="food")
- >>> print(q)#hit the database
6)-可以用get方法检索一个数据
- >>> one_entry = Entry.objects.get(pk=1)
get()和filter()还是有区别的,如果没有可以匹配的query,则get()会放回一个DoseNotExist的错误,这个exception是model class的一个参数。相似的,如果是有多个数据匹配get(),则会出现MultipleObjectReturned的错误。
7)-其他的QuerySet方法
完整的方法介绍在这里QuerySet API Reference
选前5个数据:
- >>> Entry.objects.all()[:5]
- >>> Entry.objects.all()[5:10]#从第6个到第10个
通常对QuerySet进行切片会返回一个新的QuerySet,有一个例外就是,如果用python中的step切片语法,就会对原QuerySet进行处理然后得到一个新的QuerySet:
- >>> Entry.objects.all()[:10:2]
以下两句是相同的:
- >>> Entry.objects.order_by('headline')[0]
- >>> Entry.objects.order_by('headline')[0:1].get()
8)-Field lookups
在QuerySet的方法(filter,get,exclude)的参数列表中加入Field lookups作为限制条件:
- >>> Entry.objects.filter(pub_date__lte='2006-01-01')
相当于SQL:
- SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
思考:python能够定义一个函数,是它接收正在运行计算中的变量,更多的理解移步python官网:Keyword Arguments
一般在lookups中的都是用field名的,有一种情况例外,ForeignKey,可以在field名字后面加上 _id , 后面的值是这个外部model的id值:
- >>> Entry.objects.filter(blog_id__exact=4)
若传个不存在的关键字,lookup函数会产生TypeError的错误。
database API有很多lookup类型,完备的资料在这里:field lookup reference. 下面来看一些常用的例子:
exact
- >>> Entry.objects.get(headline__exact="Man bites dog")
相当于SQL
- SELECT ... WHERE headline = 'Man bites dog';
iexact
- >>> Blog.objects.get(name__iexact="beatles blog")
SQL
- SELECT ... WHERE headline LIKE '%Lennon%';
相似的还有icontains
还有startswith, endswith等方法,全部的方法得去这里了field lookup reference.
9)-Lookups 能够拓展relationships
django有一个强大且直观的方法来处理数据的relationships,可以自动的帮助你处理SQL中的JOINs操作。使用很简单,只需要用跨model的相关的field的名称,然后用双下划线 __来连接就行了。下例中是获得所有的Entry的数据,条件是Entry中的Blog参数的名字是“Beatles Blog”:
- >>> Entry.objects.filter(blog__name__exact='Beatles Blog')
这种span可以任意深的去关联数据。也可以反向来用,例如从Blog中反向找entry:
- >>> Blog.objects.filter(entry__headline__contains='Lennon')
如果要用filter去处理多个关系的时候,而且中间的某个model没有满足filter的条件,那么,lookup不会报错,而是会认为这个中间的model的field是空的(NULL值),但是是存在的。例如:
- Blog.objects.filter(entry__authors__name='Lennon')
如果没有author跟entry连接,lookup不会报错,他会认为有一个空值的entry的。但是如果你明确指定了,如下:
- Blog.objects.filter(entry__authors__name__isnull=True)
那就会返回这样满足条件的Blog了,说明他存在嘛。
如果你不想要这种结果,那就应该这样写:
- Blog.objects.filter(entry__authors__isnull=False,
- entry__authors__name__isnull=True)
注意以上两种的区别,一个是不存在的,一个是确实存在而且想过滤掉某些干扰数据的。
今天先到这儿!
django学习之Model(三)QuerySet的更多相关文章
- Django学习笔记(三)—— 型号 model
疯狂暑期学习 Django学习笔记(三)-- 型号 model 參考:<The Django Book> 第5章 1.setting.py 配置 DATABASES = { 'defaul ...
- 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 学习之DRF (三)
Django学习之DRF-03 视图集 1.视图集介绍 2.视图集基本使⽤ 1.需求 使⽤视图集获取列表数据和单⼀数据 2.实现 class BookInfoV ...
- Django 学习笔记(三)模板导入
本章内容是将一个html网页放进模板中,并运行服务器将其展现出来. 平台:windows平台下Liunx子系统 目前的目录: hello ├── manage.py ├── hello │ ├── _ ...
- django学习之Model(五)MakingQuery
接着上篇. 10-一次更新多个对象 有时想要对QuerySet中的所有对象的某一个field来设定一个值,这时候可以像下边这样用update(): # Update all the headlines ...
- django学习笔记(三)模型
1.创建一个django app: python manage.py startapp books 2.validate 命令检查你的模型的语法和逻辑是否正确.一旦你觉得你的模型可能有问题,运行 py ...
- 07.Django学习之model进阶
一 QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. >>> Entry.objects.all( ...
- Django学习之model进阶
一 QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. >>> Entry.objects.al ...
随机推荐
- [转] iOS多线程编程之NSOperation和NSOperationQueue的使用
<iOS多线程编程之NSThread的使用> 介绍三种多线程编程和NSThread的使用,这篇介绍NSOperation的使用. 使用 NSOperation的方式有两种, 一种是用定义好 ...
- step_by_step_G+入门-在线服务
第一步:先大概介绍下我们的窗体的布局框架,窗体大体分为以下3大块: 顶部:也就是大的模块划分(比如首页,软件管家,在线服务等) 内容区域:根据选择的不同的顶部模块,进行不同的内容展示: 底部:设置,下 ...
- 帝国cms7.0调用出栏目下的东西
打开帝国后台,新建一个栏目,简历一个封面模板为 abc,套用一个封面栏目. [e:loop={"select * from {$dbtbpre}enewsclass where classi ...
- 转: js中的getYear()函数的问题(推荐用 getFullYear())
用了JS的getYear()方法,但是发现生成的代码竟然有108(本应该是2008),发现这是firefox下的问题. 然后google了一下,发 现原来是这样的:var today = new da ...
- spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jetty,Restful-jersey等)
在实战中学习,模仿博客园的部分功能.包括用户的注册,登陆:发表新随笔,阅读随笔:发表评论,以及定时任务等.Entity层设计3张表,分别为user表(用户),essay表(随笔)以及comment表( ...
- Spring-data-redis: 分布式队列
Redis中list数据结构,具有"双端队列"的特性,同时redis具有持久数据的能力,因此redis实现分布式队列是非常安全可靠的.它类似于JMS中的"Queue&qu ...
- Oracle 存储过程DEMO
); cursor isbns is select ISBN,id from librarys; bn isbns%rowtype; begin for bn in isbns loo ...
- DataTable.AcceptChanges方法有何用处
提交自上次调用 AcceptChanges 以来对该表进行的全部更改. 调用 AcceptChanges 后,再用 DataAdapter.Update() 不会有不论什么新数据被更新到数据库中.那- ...
- Struts2之—集成Json插件实现Ajax
上篇博客介绍了Struts2中自己定义结果集实现Ajax,也分析了它的缺点:这样自己定义的结果集,写死了,不能做到client须要什么数据就传什么数据:Struts2之-自己定义结果集实现aja ...
- C - N皇后问题(搜索)
Description 在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上. 你的任务是,对于给定的N,求出有多少种合 ...