接着上篇。

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的更多相关文章

  1. Django学习笔记(五)—— 表单

    疯狂的暑假学习之  Django学习笔记(五)-- 表单 參考:<The Django Book> 第7章 1. HttpRequest对象的信息 request.path         ...

  2. django学习之Model(二)

    继续(一)的内容: 1-跨文件的Models 在文件头部import进来,然后用ForeignKey关联上: from django.db import models from geography.m ...

  3. django学习之Model(一)

    认认真真学Django,从现在开始. 学习资料来源于官方网站:https://docs.djangoproject.com/en/1.6/ 1-新建一个models.py from django.db ...

  4. Django 学习笔记(五)模板标签

    关于Django模板标签官方网址https://docs.djangoproject.com/en/1.11/ref/templates/builtins/ 1.IF标签 Hello World/vi ...

  5. django学习之Model(四)MakingQuery

    上一篇写到MakingQuey中的filter,本篇接着来. 10)-扩展多值的关系 如果对一个ManyToManyField或ForeignKey的表进行filter过滤查询的话,有2中方法可以用. ...

  6. django学习之Model(三)QuerySet

    接下来主要学习Models中的Making queries 写好models.py后,django会自动提供一个数据库的抽象API,来实现CRUD(create, retrieve, update, ...

  7. Django学习笔记第五篇--实战练习一--查询数据库并操作cookie

    一.启动项目: django-admin start mysite1 cd mysite1 python manage.py startapp loginapp 根据上文敲命令就可以创建好了一个项目结 ...

  8. python Django 学习笔记(五)—— Django admin自动管理界面

    1,激活管理界面 修改settings.py MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.c ...

  9. django 学习之model操作(想细化)

    一.Field选项 null=True 数据库为空 blank=True admin相关为空 choices:choices意味着静态数据的变化不会太大. db_column: 用于此字段的数据库的列 ...

随机推荐

  1. js实现睡眠

    //js暂停函数 function Pause(obj, iMinSecond) { if (window.eventList == null) window.eventList = new Arra ...

  2. Maximum & Minimum Depth of Binary Tree

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...

  3. 如何寻找java的安装路径问题

    关于不知道JAVA安装在linux的哪 .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans ...

  4. Android 数据库ORM框架GreenDao学习心得及使用总结<二>

    转:http://blog.csdn.net/xushuaic/article/details/24496191 第五篇 查询 查询会返回符合某些特定标准的实体.你可以使用原始的SQL定制查询语句,或 ...

  5. Flink资料(3)-- Flink一般架构和处理模型

    Flink一般架构和处理模型 本文翻译自General Architecture and Process Model ----------------------------------------- ...

  6. 几种改变Activity回退栈默认行为的Intent Flag

    FLAG_与LaunchMode相比最大的不同是临时性 1.FLAG_ACTIVITY_NEW_TASK: Developer.android.com的说法: (1)在新的task中启动这个Activ ...

  7. [推荐] 查看网站使用的JS框架

    查看各大网站使用的JS框架: 打开:http://oskarkrawczyk.github.com/wtframework/ 在这个中间的图片页面上右击,Add BookMarks.(添加到书签中) ...

  8. 微软Windows 7 “可启动U盘”制作工具及使用方法,非常的简单

    目前,用“可启动U盘”替代光驱光盘安装操作系统,已经成为一种时尚(至少对没有刻录机或不愿购买光碟的群体是这样).制作“可启动U盘”的方法和工具很多,区别无非是制作的难易程度和对“U盘类型”的支持程度. ...

  9. mini KMS Activator v1.3破解激活microsoft Office 2010 RTM

    利用mini KMS Activator v1.3破解激活microsoft Office 2010 RTM方法,只是为体验office而做测试使用的哦...大家觉得好就自觉购买正版去... 使用步骤 ...

  10. Android 获取屏幕分辨率

    原文:Android 获取屏幕分辨率 得到一个屏幕尺寸的三种方法如下:        // 通过WindowManager获取        DisplayMetrics dm = new Displ ...