django学习之Model(五)MakingQuery
接着上篇。
10-一次更新多个对象
有时想要对QuerySet中的所有对象的某一个field来设定一个值,这时候可以像下边这样用update():
# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
这样使用的update()只能是没有关联关系的model或者有ForeignKey的model。如果是有ForeignKey的话,像下边这样用:
>>> b = Blog.objects.get(pk=1) # Change every Entry so that it belongs to this Blog.
>>> Entry.objects.all().update(blog=b)
update()会立即生效并返回被query匹配的行的个数。但是如果有的行已经有了新的值,则可能与update()返回的个数不相等。QuerySet的update()只有一个限制条件,就是只能作用于一个数据表(database table),也就是model的主table。可以根据相关联的field来过滤一个query,但是只能update model的主表中的columns。例如:
>>> b = Blog.objects.get(pk=1) # Update all the headlines belonging to this Blog.
>>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same')
要知道update()方法直接会转换为SQL语句,也可以做批量的update。不会进行任何save()操作的,也不会发出pre_save()或者post_save()的信号(这个信号是调用save()方法的顺序),也不会用auto_now这个field选项的。如果想要对QuerySet的每一个实例都使用save()方法的话,只要遍历这个QuerySet,用for循环就行:
for item in my_queryset:
item.save()
用update()方法时,也可以用F()对象来进行更新,根据此model中的另一个field值。尤其是当增加技术的时候很好用,下例就是一个增加pingback计数的用法:
>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
然而,与在filter中的F()对象不同的是,不能对一个在update中的F()使用joins功能,只能引用要更新的model中的field,如果师徒对一个F()对象使用jions,会有FieldError错误:
# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))
11-相关的对象
在一个model中定义了一个关系时(例如,ForeignKey, OneToOneField, ManyToManyField),这个model的实例会有很方便的API来接触相关对象。像前边讲到的例子,一个Entry的对象e,可以e.blog来连接Blog的对象blog。背后其实用到的是python的语法。
对于这些关联关系的另一面来说,django也会有一些其他的API。例如,Blog的对象blog可以连接到一系列的Entry的对象,通过方法entry_set,像这样:b.entry_set.all()。
下边的所有例子都是用到了前文提到的Blog, Author, Entry。
1)-一对多关系
如果一个model有一个ForeignKey, 这个model的实例就会有连接他的foreign关系的对象的接口:
>>> e = Entry.objects.get(id=2)
>>> e.blog # Returns the related Blog object.
上边代码,Entry中有一个ForeignKey指向Blog,所以,blog可以看作是Entry的一个成员,类似于对象的成员这样调用。
当然,只有save()的时候才能保存,这个是一直在强调的:
>>> e = Entry.objects.get(id=2)
>>> e.blog = some_blog
>>> e.save()
如果ForeignKey的field中有一个参数null=True,那么可以分配个None值来解除这个Foreign关系:
>>> e = Entry.objects.get(id=2)
>>> e.blog = None
>>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
当第一次接触到一个对象的database的时候,取到的值会被缓存下来,接下来如果还用到的话,就不用去接触database了,而是直接从缓存中取数据,这是在one-to-many这样的关系时的情况,记得前边讲到过,其他情况下,这样是不会产生缓存的,还是会第二次hit the database:
>>> e = Entry.objects.select_related().get(id=2)
>>> print(e.blog) # Doesn't hit the database; uses cached version.
>>> print(e.blog) # Doesn't hit the database; uses cached version.
2)-把这种关系反过来
Entry中有一个ForeignKey关系到Blog,上边的例子是e.blog,那如果已知b是Blog的对象,对应的b.entry会是什么呢?实际上,是会返回所有的entry的对象的一个QuerySet,这个方法市一中Manager,但要明确并不是b.entry这样写,而是下面例子中的F00_set,其中F00是含有ForeignKey的model的实例(例如entry),注意是小写的entry:
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.all() # Returns all Entry objects related to Blog. # b.entry_set is a Manager that returns QuerySets.
>>> b.entry_set.filter(headline__contains='Lennon')
>>> b.entry_set.count()
当然这个entry_set是可以重写的,如果定义了
blog = ForeignKey(Blog, related_name='entries')
那么:
>>> b = Blog.objects.get(id=1)
>>> b.entries.all() # Returns all Entry objects related to Blog. # b.entries is a Manager that returns QuerySets.
>>> b.entries.filter(headline__contains='Lennon')
>>> b.entries.count()
除了在前文中提到的对象检索中的QuerySet的方法,ForeignKeyManager还有额外的方法来处理相关联的对象。完备的资料参考related objects reference。
add(obj1, obj2, ...)
把指定的model的对象加到相关联的model的对象中。(应该是可以把entry加到blog中)
create(**kwargs)
创建一个新的对象,保存并把放进相关联的对象中。返回新创建的对象。
clear()
把相关联的对象中的所有对象都移除。
对相关联的对象一次添加多个对象,可以像下面这样写:
b = Blog.objects.get(id=1)
b.entry_set = [e1, e2]
e1和e2可以使完整的Entry的实例,也可以是整数型的pirmary key的值。
如果有clear()方法,那么在entry_set添加新的对象之前,之前的那些对象都会被移除,如果没有clear()方法,那么添加entry_set不回移除之前的对象。
这一段讨论的检索方法,都会立即生效于database,每个例子中的添加和删除都会自动save,所以不用再调用save方法了。
3)-Many-to-Many关联
这种关联的两头的对象都有自动的API,来连接另一端,也就是可以理解为关联的两头是地位相等的,对称的。这个API就像上面提到的one-to-many时反过来的那个 ”多到一“ 的那样操作。唯一的区别是参数的名字上:定义了ManyToManyField的model用自己的field的名字,关联另一端的那个model使用定义关联的model的名字,加上_set,举个例子就明白啦:
e = Entry.objects.get(id=3)
e.authors.all() # Returns all Author objects for this Entry.
e.authors.count()
e.authors.filter(name__contains='John') a = Author.objects.get(id=5)
a.entry_set.all() # Returns all Entry objects for this Author.
当然,Entry中定义了ManyToManyField,Author是此关联的另一端,所以a.entry_set.all()。
就像ForeignKey, ManyToManyField可以定义一个related_name,上边的例子中也可以定义Entry中的related_name='entries',则entry_set就可以用entries代替了。
4)-One-to-one关联
这种关联与many-to-many关联类似,如果在一个model中定义了OneToOneField,这个model就可以用简单的方法来连接到相关联的那个model:
class EntryDetail(models.Model):
entry = models.OneToOneField(Entry)
details = models.TextField() ed = EntryDetail.objects.get(id=2)
ed.entry # Returns the related Entry object.
不同的“反过来”的query,one-to-one关联中的被关联的model也有一种Manager,只不过这个Manager返回的只是一个对象,而不是一些对象,很好理解,因为one-to-one关系嘛:
e = Entry.objects.get(id=2)
e.entrydetail # returns the related EntryDetail object
如果关联的model没有对象的话,会有错误DoesNotExist。
这种“反过来”也可以给对象赋值为一个对象,就像顺序关联的时候那样:
e.entrydetail = ed
5)-为什么“反过来”的关联是可能的呢?
别的对象关联图要求必须在关联的两端都要定义这种关联关系。django开发者认为i这是一种对DRY(Don't Repeat Yourself)准则的践踏(- -!),所以django只要求在一端来定义关联关系就可以了。
想像一下,凭感觉来讲,在的django中,貌似是直到别的model class被加载的时候,这个定义了关联关系的model class才知道自己关联到了哪里,也就是说,其实之前定义了关联的model class是不知道自己要被关联到哪里的,按道理说这怎么可能实现呢?
其实答案就在settings.py文件中INSTALLED_APPS中,当每个model被第一次加载的时候,django会在INSTALLED_APPS中列出来这些model,然后在内存中记录下“反过来”的关联,来备用。基本的,INSTALLED_APPS的一个作用就是告诉django整个model的控制器。
6)-相关联的对象的查询
包含相关联的对象的查询与普通的查询是一样的,有可以用对象的实例来作为filter条件,也可以用primary key。例如,Blog的对象是blog,其id=5,则如下:
Entry.objects.filter(blog=b) # Query using object instance
Entry.objects.filter(blog=b.id) # Query using id from instance
Entry.objects.filter(blog=5) # Query using id directly
最后-不妨看看原生的SQL
如果发现写一个SQL的query来给django来用太麻烦,不妨自己手写一个SQL代码段,django也提供了一些选项可以写原生的SQL语句,可以参考 Performing raw SQL queries.
特别要注意的是,django的databse的表层(layer)只不过仅仅是对于你的database的一个接口,一个界面(interface),除了django当然也可以用其他的方法来处理database。
MakingQuery到此结束,感觉囫囵吞枣的看来一遍,还有很多地方只能是猜到大概的意思,理解不深,对于SQL需要更多的学习,对于实战经验也需要更多的积累。
django学习之Model(五)MakingQuery的更多相关文章
- Django学习笔记(五)—— 表单
疯狂的暑假学习之 Django学习笔记(五)-- 表单 參考:<The Django Book> 第7章 1. HttpRequest对象的信息 request.path ...
- 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.IF标签 Hello World/vi ...
- django学习之Model(四)MakingQuery
上一篇写到MakingQuey中的filter,本篇接着来. 10)-扩展多值的关系 如果对一个ManyToManyField或ForeignKey的表进行filter过滤查询的话,有2中方法可以用. ...
- django学习之Model(三)QuerySet
接下来主要学习Models中的Making queries 写好models.py后,django会自动提供一个数据库的抽象API,来实现CRUD(create, retrieve, update, ...
- Django学习笔记第五篇--实战练习一--查询数据库并操作cookie
一.启动项目: django-admin start mysite1 cd mysite1 python manage.py startapp loginapp 根据上文敲命令就可以创建好了一个项目结 ...
- python Django 学习笔记(五)—— Django admin自动管理界面
1,激活管理界面 修改settings.py MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.c ...
- django 学习之model操作(想细化)
一.Field选项 null=True 数据库为空 blank=True admin相关为空 choices:choices意味着静态数据的变化不会太大. db_column: 用于此字段的数据库的列 ...
随机推荐
- oracle日期函数集锦
oracle 中select TO_CHAR(sysdate,'Mon') from dual; Question:出来是中文的“6月” 我想要英文的怎么办? Answer:select to_cha ...
- Sublime Text 增加CoffeeScript、Jade and Stylus syntax高亮
切换到Sublime Text Packages 目录: Liunx系统: cd ~/Library/Application\ Support/Sublime\ Text\ /Packages win ...
- Java 基本日期类使用(一)
一.java.util.Date Date表示特定的瞬间,精确到毫秒,其子类有Date.Time.Timestap.默认情况下输出的Date对象为:Mon Oct 13 17:48:47 CST 20 ...
- 性能监控工具javamelody与spring的集成
详细信息可以访问javamelody的官方网站 我在集成的过程中,一直出现commonHibernateDao的加载问题, 另外,根据官方文档,如果你的应用与monitoring-spring.xml ...
- JAVA 类加载器 第14节
JAVA 类加载器 第14节 今天我们将类加载机制5个阶段中的第一个阶段,加载,又叫做装载.为了阅读好区分,以下都叫做装载. 装载的第一步就是要获得二进制的字节流,它可以从读.class文件获得,也可 ...
- cookie简介
上例子 1.首先要用php创建cookie发送给客户端,利用setcookie()方法即可 <?php /* * * @Authors peng--jun * @Email 1098325951 ...
- vb sqlite 使用 litex
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal ...
- 函数指针 如:void (*oper)(ChainBinTreee *p)
在C语言中,一个函数总是占用一段连续的内存区,而函数名就是该函数所占内存区的首地址.我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量,使该指针变量指向该函数.然后通过指针变量就可以找到并调用 ...
- C# Socket SSL通讯笔记
一.x.509证书 1.制作证书 先进入到vs2005的命令行状态,即:开始-->程序-->Microsoft Visual Studio 2005-->Visual Studio ...
- #include <array>
array是静态数组,在栈上,不可以变长 vector比array更常用 不需要变长,容量较小,用array 需要变长,容量较大,用vector 1 array 1 array新数组 //std::a ...