乃拼命了邪

接大家拜我的私网站《刘江的博客及课程》:www.liujiangblog.com

出人意料看到这题材之时段,是勿是感到甚奇怪,努力不应当是正朝着的,积极的一个词吗?怎么会化为了伪命题了吧,那大家还还做什么努力,直接就顺其自然就足以了咔嚓。

# 主要分享Python 及Django教程以及相关的博客

乃想错了,这里说之君的着力是个伪命题是发案由之,别着急,先任自己说那零星码事。

3.2.2 查询操作

6.15节包含有模型相关的API解释。
末尾的情节据悉如下的一个博客应用模型:

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):              # __unicode__ on Python 2
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):              # __unicode__ on Python 2
        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()

    def __str__(self):              # __unicode__ on Python 2
        return self.headline

首先码事是起网上来看的,原文怎么样,已经记不极端彻底矣,大概的意思是这样的:有一个男生,学习好朴素,每天还全力以赴的管教材上之学识且记了下来,但是考试还是勿能够考查了别人,而且他看看班级第一平常为未曾多努力学习,经常以那玩,还能够考第一,自己充分费解,后来测验结果还是这么,老师为他的卷子写了同一句批语:学习不克独靠努力,还要用对艺术。学生了解了自己存在的题材,自己正之后,不仅自己平时轻松了森,成绩呢大都不是率先便是次。

3.2.2.1 创建对象

倘若模型在mysite/blog/models.py文件中,那么创建对象的法子如下:

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()

每当后台,这会运行一久SQL的INSERT语句。如果您无形的调用save()方法,Django不会立刻将该操作反映至数据库被。save()方法没有回值,它可以接受部分外加的参数。

如想如果一行代码完成地方的操作,请以creat()方法,它可概括save的步子:

b = Blog.objects.create(name='Beatles Blog', tagline='All the latest Beatles news.')

还有一样桩事,是以自家身上有的,我在刚学编程的时光,一点基础为尚无,而身边发生局部校友是发功底,有一定之逻辑概念。刚起教师说,这个要差不多敲代码,多练习,每天先管课堂笔记敲了,然后又将作业做了,有时光尽管多敲几全套,慢慢的产出了一个题目,就是自为此一个晚自习加上回的时光去举行截止这些,而同学在后自习只所以了一个时便做得了了作业,我却用了5只钟头没做截止,这样了几乎不行,我虽开思索自己哪里出了问题,发现除此之外代码敲的慢,还有一个至关重要就是是自家的办法来问题,虽然每天敲代码5单多小时,但是效率不强,还不如同学1独小时的频率高。所以有时候不是不遗余力就是得的。

3.2.2.2 保存对象

运用save()方法,保存对数据库内一度发目标的改。例如:如果已在b5对象在数据库内:

>>> b5.name = 'New name'
>>> b5.save()

每当后台,这会运行一长达SQL的UPDATE语句。如果您无亮的调用save()方法,Django不会立刻用拖欠操作反映至数据库中。

什么,看了当下半只稍故事,知道为何我会说努力是个伪命题了吧。

保留外键和多对准大多字段

保留一个外键字段和保留普通字段没什么区别,只是如果注意值的种要对。下面的例证,有一个Entry的实例entry和一个Blog的实例cheese_blog,然后把cheese_blog作为值赋给了entry的blog属性,最后调用save方法开展保存。

>>> from blog.models import Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()

差不多针对几近字段的保存稍微有接触分,需要调用一个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)

如您指定要补充加了左类型的对象,Django会抛来异常。

今说努力是只伪命题。是梦想大家在全力的当儿肯定要顾几碰。

3.2.2.3 检索对象

思要由数据库内搜寻对象,你得根据模型类,通过管理器(Manager)构造一个查询结果集(QuerySet)。

每个QuerySet代表有数据库对象的汇聚。它可涵盖零个、一个或者多只过滤器(filters)。Filters缩小查询结果的限制。在SQL语法中,一个QuerySet相当给一个SELECT语句,而filter则一定给WHERE或者LIMIT一好像的子句。

经模型的Manager获得QuerySet,每个模型起码有一个Manager,默认情况下,它为称呼“objects”,可以经过模型类直接调用它,但无能够经过模型类的实例调用它,以此实现“表级别”操作以及“记录级别”操作的要挟分离。如下所示:

>>> 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."

1、方向很要紧。
实质上自古,我们便信奉勤劳,努力会给咱了得再好,不过为,时代以变更,我们不得不说,有的上,我们要把自己的思升级换代一下。有无来听罢如此一句话,越努力进一步幸运。但是尚未告知您前提是,目标方向肯定要是对,不然,你更加努力就会受您越走越远,偏离了团结的趋向,你还拼命以有毛线用吗。

搜索所有目标

行使all()方法,可以收获有张表的具备记录。

>>> all_entries = Entry.objects.all()

2、你用来头脑。
乃想,古代由首都到南京八百里加急,还亟需或多或少龙才会及吧,而今天吧,你就待几只钟头即能到。说明什么,说明我们以保持原有的好之习惯的根基及,需要学会承受新鲜事物,有再度会节省时间,提高效率的法,为什么不用为。觉得好拼命一万小时便是专家了?别傻了,所谓的一万时里,也是说的苦心练习,是发生思想的再练习,而未是熬在头去乱闯。一味的坚持不自然会马到成功,但是加上自己之独门思想的力,起码会被你开打从事来节省成千上万时刻,就会见来生命力去发展协调之其它兴趣爱好一类似的。

过滤器检索对象

发出2只点子可以为此来过滤QuerySet的结果,分别是:

filter(kwargs):返回一个根据指定参数查询出来的QuerySet
exclude(
kwargs):返回除了因指定参数查询出来结果的QuerySet
其中,**kwargs参数的格式必须是Django设置的一部分字段格式。

例如:

Entry.objects.filter(pub_date__year=2006)

她一样于:

Entry.objects.all().filter(pub_date__year=2006)

链式过滤

filter和exclude的结果还是是单QuerySet,因此它可继续给filter和exclude,这虽形成了链式过滤:

>>> Entry.objects.filter(
...     headline__startswith='What'
... ).exclude(
...     pub_date__gte=datetime.date.today()
... ).filter(
...     pub_date__gte=datetime(2005, 1, 30)
... )

(译者:这里用注意的是,当于拓展超越关系的链式过滤时,结果或者与您想像的非均等,参考下面的跳多值关系查询)

吃过滤的QuerySets都是唯一的

各级一样糟糕过滤,你都见面获取一个崭新的QuerySet,它与事先的QuerySet没有其它关联,可以了独立的被保留,使用与录取。例如:

>>> 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())

事例中之q2和q3虽然由于q1得来,是q1的子集,但是都是自立存在的。同样q1也无见面遭遇q2和q3的影响。

QuerySets都是懈怠的

一个创立QuerySets的动作不会见即刻导致其他的数据库行为。你可堆栈所有的filter动作一整天,Django不会运行任何实际的数据库查询动作,直到QuerySets被交给(evaluated)。

简而言之就是,只有遇到一些特定的操作,Django才会将具有的操作体现到数据库内,否则其只是保存在内存和Django的面中。这是一样种植提高数据库查询效率,减少操作次数之优化规划。看下的例证:

>>> 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)

方的例证,看起执行了3赖数据库访问,实际上只是于print语句子时实行了1不好访。通常情况,QuerySets的寻不会见即刻实施实际的数据库查询操作,直到出现类似print的乞求,也就是是所谓的evaluated。具有有什么操作会触发evaluated,请查看6.15.8章节。

3、努力不是召开表面功夫,还索要不停的重复,专注做一样项事,把事情完了最好致。
试想一下,你想奋力给祥和了之再次好,今天关押正在开煤炭致富,就错过开煤炭,明天羁押在开销售挣钱,又失去开销售,哪怕你足足努力,足够好,也会见吃旁边那个一直于向着自己之取向发展的外让过,而若,在渐渐的前头实施中见面发现,你虽发出了一代底景致,但是就算像是镜花水月,不见面长久。最好之永远都是能密切水长流,可持续发展的工作。思考一下,你是怎么开的?你是不是出如此的毛病,如果发,赶紧拿它们改掉。

搜单一对象

filter方法始终返回的凡QuerySets,那恐惧光来一个对象符合过滤条件,返回的呢是含有一个目标的QuerySets。

若您确定你的摸索只见面获一个靶,那么您可以使Manager的get()方法来直接回这个目标。

>>> one_entry = Entry.objects.get(pk=1)

在get方法吃你可以使用其它filter方法的询问参数,一模子一样。

只顾:使用get()方法以及动filter()方法然后经过[0]的不二法门分片,有着不同之地方。看似两者都是收获单一对象。但是,如果在查询时并未匹配到对象,那么get()方法将摒弃来DoesNotExist异常。这个可怜是模型类的一个性,在上头的例子中,如果无存在主键为1的Entry对象,那么Django将抛出Entry.DoesNotExist异常。

恍如地,在动get()方法查询时,如果结果越1个,则会废弃来MultipleObjectsReturned异常,这个特别与否是模型类的一个属性。

4、计划之首要。前面说了那么多,你还亟需举行的同宗事便是,把你的方向,你的全力,输出出来,落实到你会看的显现之成才,这样您才能够发出动力去逐渐改变自己,到下你就算见面发觉,在不注意之间,你已做到了立您当贵的对象。

其它QuerySet方法

查看6.15.8沾更多不同的QuerySet方法有关消息

七年尽管是一生,这个七年,让大家见证自己之成人。
愿意你会成长为你想之旗帜。

QuerySet以限制

行使类Python对列表进行切开的方好对QuerySet进行界定取值。它一定给SQL语句被的LIMIT和OFFSET子句。参考下面的例子:

>>> Entry.objects.all()[:5]      # 返回前5个对象
>>> Entry.objects.all()[5:10]    # 返回第6个到第10个对象

在意:不支持负索引!例如 Entry.objects.all()[-1]是勿允许的

一般性情况,切片操作会返回一个初的QuerySet,并且不会见吃立即执行。但是有一个不同,那就是指定步长的当儿,查询操作会立刻在数据库内实行,如下:

>>> Entry.objects.all()[:10:2]

设若使博得单一的靶子要未是一个列表(例如,SELECT foo FROM bar LIMIT
1),可以大概地动用索引而不是片。例如,下面的话语返回数据库被因题目排序后的率先漫长Entry:

>>> Entry.objects.order_by('headline')[0]

它们一定给:

>>> Entry.objects.order_by('headline')[0:1].get()

小心:如果没匹配到对象,那么首先栽方法会抛来IndexError异常,而第二种植方法会丢弃来DoesNotExist异常。

也就是说在采用get和片的时候,要留心查询结果的素个数。

字段查询

字段查询其实就算是filter()、exclude()和get()方法的要紧字参数。
夫主导格式是:field__lookuptype=value,注意其中凡对产划线。
例如:

>>> Entry.objects.filter(pub_date__lte='2006-01-01')
# 相当于:
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

个中的field必须是范中定义的filed之一。但是生一个两样,那就算是ForeignKey字段,你可吧其长一个“_id”后缀(单下划线)。这种场面下键值是外键模型的主键原生值。例如:

>>> Entry.objects.filter(blog_id=4)

假定您传递了一个野鸡的键值,查询函数会抛出TypeError异常。
Django的数据库API支持20差不多种查询类型,完整的参考手册在6.15节,下面介绍部分常用的:

exact:

默认类型。如果你切莫提供查询类型,或者根本字参数不含一个双下划线,那么查询类型就是其一默认的exact。

>>> Entry.objects.get(headline__exact="Cat bites dog")
# 相当于
# SELECT ... WHERE headline = 'Cat bites dog';
# 下面两个相当
>>> Blog.objects.get(id__exact=14)  # Explicit form
>>> Blog.objects.get(id=14)         # __exact is implied

iexact:

不区分轻重缓急写。

>>> Blog.objects.get(name__iexact="beatles blog")
# 匹配"Beatles Blog", "beatles blog",甚至"BeAtlES blOG".

contains:

代表包含的意!大小写敏感!

Entry.objects.get(headline__contains='Lennon')
# 相当于
# SELECT ... WHERE headline LIKE '%Lennon%';
# 匹配'Today Lennon honored',但不匹配'today lennon honored'

icontains:

contains的大小写不灵活模式。

startswith和endswith

坐什么开和坐什么最后。大小写敏感!

istartswith和iendswith是不区分轻重缓急写的模式。

超越关系查询

Django提供了强硬又直观的办法缓解越关联的查询,它于后台自动执行包含JOIN的SQL语句。要超过某个关联,只待以关联的模型字段名称,并采用对生划线分隔,直至你想使的字段(可以链式跨越,无限跨度)。例如:

# 返回所有Blog的name为'Beatles Blog'的Entry对象
# 一定要注意,返回的是Entry对象,而不是Blog对象。
# objects前面用的是哪个class,返回的就是哪个class的对象。
>>> Entry.objects.filter(blog__name='Beatles Blog')

相反的同,如果假定引用一个反向关联,只需要运用模型的粗写名!

# 获取所有的Blog对象,前提是它所关联的Entry的headline包含'Lennon'
>>> Blog.objects.filter(entry__headline__contains='Lennon')

倘你以密密麻麻关联中展开过滤而其中某中间型没有满足过滤条件的价,Django将把其看成一个缺损的(所有的价值都也NULL)但是合法的目标,不见面弃来任何特别要不当。例如,在下面的过滤器中:

Blog.objects.filter(entry__authors__name='Lennon')

假如Entry中尚无涉嫌任何的author,那么其将用作其并未name,而休见面因为没author
引发一个谬误。通常,这是比较吻合逻辑的处理方式。唯一可能为您困惑的是当你下isnull的当儿:

Blog.objects.filter(entry__authors__name__isnull=True)

随即将回来Blog对象,它关系的entry对象的author字段的name字段为空,以及Entry对象的author字段为空。如果您不欲后人,你得这么描写:

Blog.objects.filter(entry__authors__isnull=False,entry__authors__name__isnull=True)

过多值关系查询

极基本的filter和exclude的第一字参数就生一个,这种情景颇好明。但是当重点字参数有多独,且是跳外键或者基本上对多之情形下,那么就算比较复杂,让丁迷惑了。我们看下面的例子:

Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)

当下是一个超外键的,两独过滤参数的询问。此时咱们解两个参数之间属于-与“and”的干,也就是说,过滤出来的BLog对象对应之entry对象要同时满足上面两个条件。这点异常好掌握。但是,看下的用法:

Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)

把少单参数拆起来,放在两只filter调用里面,按照我们眼前说罢的链式过滤,这个结果当跟点的事例一样。可其实,它不同等,Django在这种场面下,将少独filter之间的涉及计划吧-或“or”,这真是让丁头疼。
大多对准大多涉及下的多值查询及外键foreignkey的情景亦然。

但,更头疼的来了,exclude的国策设计的同时跟filter不均等!

Blog.objects.exclude(entry__headline__contains='Lennon',entry__pub_date__year=2008,)

立马会免去headline中含有“Lennon”的Entry和于2008年颁布的Entry,中间是一个-和“or”的关联!

这就是说只要解以满足上面两只标准化的目标,该怎么处置也?看下面:

Blog.objects.exclude(
entry=Entry.objects.filter(
    headline__contains='Lennon',
    pub_date__year=2008,
),
)

(译者:有没有来良坑爹的觉得?所以,建议以碰到过关系之多值查询时,尽量使用Q查询)

使用F表达式引用模型的字段

至目前为止的例子中,我们且是以模型字段与常量进行比。但是,如果你想拿模型的一个字段与跟一个型的另外一个字段进行比该怎么处置?

使用Django提供的F表达式!

比如说,为了追寻comments数目多于pingbacks数目的Entry,可以组织一个F()对象来引用pingback
数目,并于询问中使该F()对象:

>>> from django.db.models import F
>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks'))

Django支持对F()对象进行加、减、乘、除、取模以及幂运算等算术操作。两个操作数可以是常数和任何F()对象。例如查找comments数目比pingbacks两加倍还要多之Entry,我们得以如此写:

>>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)

为了查询rating比pingback和comment数目总和要多少的Entry,我们可如此形容:

>>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks'))

卿还足以以F()中应用对下划线来开展跨表查询。例如,查询author的名字与blog名字一样的Entry:

>>> Entry.objects.filter(authors__name=F('blog__name'))

对此date和date/time字段,还足以加以要减去一个timedelta对象。下面的例证将赶回发布时间跨3上后被涂改的所有Entry:

>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))

F()对象还支持.bitand()和.bitor()两种植位操作,例如:

>>> F('somefield').bitand(16)
主键的快速查询方式:pk

pk就是primary
key的缩写。通常情况下,一个型的主键为“id”,所以下三单告知句之效能一样:

>>> 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)

得跨表操作:

>>> Entry.objects.filter(blog__id__exact=3) 
>>> Entry.objects.filter(blog__id=3) 
>>> Entry.objects.filter(blog__pk=3)

(译者:当主键不是id的早晚,请留心了!)

自动转义百分符号和下划线

于原生SQL语句中%标志来与众不同之意。Django帮你活动的转义了百分符号和下划线,你可跟通常字符一样使用它,如下所示:

>>> Entry.objects.filter(headline__contains='%')
# 它和下面的一样
# SELECT ... WHERE headline LIKE '%\%%';
缓存和询问集合

每个QuerySet都饱含一个缓存,用于减少对数据库的实际操作。

于新创造的QuerySet,它的缓存是空的。当QuerySet第一破吃交付后,数据库执行实际的查询操作,Django会把询问的结果保存于QuerySet的缓存内,随后的对该QuerySet的交由将用这个缓存的数目。

如想迅速之施用查询结果,降低数据库负载,你不能不善于使缓存。看下面的例证,这会导致2次实在的数据库操作,加倍数据库的载荷,同时鉴于时日不一的问题,可能以个别坏操作间数据被删去或改动或丰富,导致污染数据的问题:

>>> print([e.headline for e in Entry.objects.all()])
>>> print([e.pub_date for e in Entry.objects.all()])

为避免上面的问题,好之应用方法如下,这单生同样潮实际上的查询操作,并且维持了多少的一致性:

>>> queryset = Entry.objects.all()
>>> print([p.headline for p in queryset]) # 提交查询
>>> print([p.pub_date for p in queryset]) # 重用查询缓存

何时休会见受缓存

产生局部操作不见面缓存QuerySet,例如切片和目录。这便导致这些操作没有缓存可用,每次都见面履行实际的数据库查询操作。例如:

>>> queryset = Entry.objects.all()
>>> print queryset[5] # 查询数据库
>>> print queryset[5] # 再次查询数据库

可,如果已遍历过所有QuerySet,那么就一定给缓存过,后续的操作则会下缓存,例如:

>>> queryset = Entry.objects.all()
>>> [entry for entry in queryset] # 查询数据库
>>> print queryset[5] # 使用缓存
>>> print queryset[5] # 使用缓存

脚的这些操作都将整历QuerySet并确立缓存:

>>> [entry for entry in queryset]
>>> bool(queryset)
>>> entry in queryset
>>> list(queryset)

顾:简单的于印QuerySet并无会见起缓存,因为__repr__()调用只回全部查询集的一个切开。

3.2.2.4 使用Q对象开展复杂查询

日常filter函数里之规范且是“and”逻辑,如果你想实现“or”逻辑怎么处置?用Q查询!

Q来自django.db.models.Q,用于封装关键字参数的聚众,可以作为重点字参数用于filter、exclude和get等函数。
例如:

from django.db.models import Q
Q(question__startswith='What')

好用“&”或者“|”或“~”来组合Q对象,分别代表与或非逻辑。它用返回一个初的Q对象。

Q(question__startswith='Who')|Q(question__startswith='What')
# 这相当于:
# WHERE question LIKE 'Who%' OR question LIKE 'What%'
Q(question__startswith='Who') | ~Q(pub_date__year=2005)

你吗可以这样使用,默认情况下,以逗号分隔的且代表AND关系:

Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
# 它相当于
# SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

当第一字参数和Q对象成以时,Q对象要在前方,如下例子:

Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),question__startswith='Who',)

只要要字参数放在Q对象的前方,则会报错。
(译者:关于Q对象还有更高级的采取方式)

3.2.2.5 比较对象

假如比较单薄独模型实例,只需要运用python提供的双等号比较相符就好了。在后台,其实正如的是片独实例的主键的价值。
下面两种方式是平等的:

>>> some_entry == other_entry
>>> some_entry.id == other_entry.id

若模型的主键不曰“id”也不曾涉及,后台总是会使对的主键名字进行比较,例如,如果一个模的主键的名字是“name”,那么下面是相等的:

>>> some_obj == other_obj
>>> some_obj.name == other_obj.name

3.2.2.6 删除对象

去对象下的是delete()方法。该方式以回到给删除对象的毕竟数据及一个字典,字典包含了每种被去除对象的种以及欠类型的数量。如下所示:

>>> e.delete()
(1, {'weblog.Entry': 1})

可以批量刨除。每个QuerySet都生一个delete()方法,它能够去除该QuerySet的有成员。例如:

>>> Entry.objects.filter(pub_date__year=2005).delete()
(5, {'webapp.Entry': 5})

待专注的是,有或未是各一个靶的delete方法都被执行。如果你改写了delete方法,为了保目标吃删去,你不能不手动迭代QuerySet进行依次删除操作。

当Django 删除一个对象时,它默认使用SQL的ON DELETE
CASCADE约束,也就是说,任何有外键指向要去除对象的对象将共同让去除。例如:

b = Blog.objects.get(pk=1)
# 下面的动作将删除该条Blog和所有的它关联的Entry对象
b.delete()

这种级联的行事可以透过的ForeignKey的on_delete参数自定义。

顾,delete()是绝无仅有无于管理器上暴露出的方式。这是刻意设计之一个安康体制,用来防范你飞地求类似Entry.objects.delete()的动作,而不慎删除了装有的条目。如果您真的想抹所有的靶子,你必须明白地央求一个全然的查询集,像下这样:

Entry.objects.all().delete()

3.2.2.7 复制模型实例

虽说从未坐的措施用于复制模型的实例,但尚是老容易创建一个新的实例并将本实例的持有字段都拷贝过来。最简便易行的法子是将原来实例的pk设置为None,这会创造一个初的实例copy。示例如下:

blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
#
blog.pk = None
blog.save() # blog.pk == 2

然而以使持续的时,情况会更换得复杂,如果产生下面一个Blog的子类:

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

方的艺术还未曾关联关联对象。如果您想复制关系,你不能不手动多写一些代码,像下这样:

entry = Entry.objects.all()[0] # 一些原始的entry对象
old_authors = entry.authors.all()
entry.pk = None
entry.save()
entry.authors = old_authors # 保存新的多对多关系

3.2.2.8 批量翻新目标

采取update()方法可以批量吗QuerySet中所有的目标开展翻新操作。

# 更新所有2007年发布的entry的headline
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

您一味堪对一般性字段和ForeignKey字段使用这办法。若一旦创新一个习以为常字段,只需要提供一个初的常反复值。若一旦创新ForeignKey字段,需安装新值为汝想对的初模型实例。例如:

>>> b = Blog.objects.get(pk=1)
# 修改所有的Entry,让他们都属于b
>>> Entry.objects.all().update(blog=b)

update方法会让立即执行,并回操作匹配到的执行之数码(有或无齐要翻新的实施之多少,因为有点行或已有之新值了)。唯一的封锁是:只能看同一张数库表。你可因涉字段进行过滤,但您只能更新模型主表的字段。例如:

>>> 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语句,并及时批量实践。它不会见运作模型的save()方法,或者有pre_save或post_save信号(调用save()方法发生)或者服从auto_now字段选项。如果您想保留QuerySet中的每个条目并确保每个实例的save()方法都于调用,你切莫需要使用其他异常之函数来处理。只需要迭代它们并调用save()方法:

for item in my_queryset:
    item.save()

update方法可配合F表达式。这对批量创新同一型BWIN必赢亚洲56.net中某个只字段特别有因此。例如增加Blog中每个Entry的pingback个数:

>>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)

但,与filter和exclude子句被之F()对象不同,在update中你莫得以使用F()对象开展跨表操作,你就可引用在更新的范的字段。如果您品味使用F()对象引入另外一张表的字段,将摒弃来FieldError异常:

# THIS WILL RAISE A FieldError
>>> Entry.objects.update(headline=F('blog__name'))

3.2.2.9 关联的对象

使用本节一开始的模型,一个Entry对象e可以通过blog属性e.blog获取涉及的Blog对象。反过来,Blog对象b可以经entry_set属性b.entry_set.all()访问和它涉及的所有Entry对象。

一对多(外键)

巧往查询
直通过圆点加属性,访问外键对象:

>>> e = Entry.objects.get(id=2)
>>> e.blog # 返回关联的Blog对象

一旦专注的是,对外键的改,必须调用save方法进行保存,例如:

>>> e = Entry.objects.get(id=2)
>>> e.blog = some_blog
>>> e.save()

只要一个外键字段设置有null=True属性,那么得经为该字段赋值为None的不二法门移除外键值:

>>> e = Entry.objects.get(id=2)
>>> e.blog = None
>>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"

在首先潮针对一个外键关系进展正向访问的时节,关系对象见面给缓存。随后对同一外键关系对象的顾会用这个缓存,例如:

>>> e = Entry.objects.get(id=2)
>>> print(e.blog)  # 访问数据库,获取实际数据
>>> print(e.blog)  # 不会访问数据库,直接使用缓存的版本

请注意QuerySet的select_related()方法会递归地预填充所有的同等对多关系及缓存中。例如:

>>> e = Entry.objects.select_related().get(id=2)
>>> print(e.blog)  # 不会访问数据库,直接使用缓存
>>> print(e.blog)  # 不会访问数据库,直接使用缓存

反向查询

若一个模产生ForeignKey,那么该ForeignKey所针对的外键模型的实例可以由此一个管理器进行反为查询,返回源模型的所有实例。默认情况下,这个管理器的讳啊FOO_set,其中FOO是出自模型的小写名称。该管理器返回的查询集可以为此前提到的法展开过滤跟操作。

>>> 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()

若得于ForeignKey字段的概念着,通过安装related_name来重写FOO_set的名字。举例说明,如果你修改Entry模型blog
= ForeignKey(Blog, on_delete=models.CASCADE,
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()

动用从定义之反向管理器

默认情况下,用于反朝关系的RelatedManager是欠型默认管理器的子类。如果你想为一个查询指定一个不同之管理器,你得运用下的语法:

from django.db import models

class Entry(models.Model):
    #...
    objects = models.Manager()  # 默认管理器
    entries = EntryManager()    # 自定义管理器

b = Blog.objects.get(id=1)
b.entry_set(manager='entries').all()

自然,指定的自定义反朝管理器也得以调用它的自定义方法:

b.entry_set(manager='entries').is_published()

拍卖涉嫌对象的另外方法

除外在前方“检索对象”一节中定义的QuerySet方法之外,ForeignKey管理器还产生另措施用于拍卖涉的目标集合。下面是每个方法的席卷,完整的底细可以以涉6.15.4饱受找到。

add(obj1, obj2, …):添加指定的型对象及事关的靶子集中。
create(**kwargs):创建一个初的靶子,将其保存并放在事关的目标集中。返回新创办的靶子。
remove(obj1, obj2, …):从涉嫌的对象集中删除指定的范对象。
clear():清空关联的目标集。
set(objs):重置关联的靶子集。

设若一旦一次性为关系的目标集赋值,使用set()方法,并吃她赋值一个可迭代的目标集合或者一个主键值的列表。例如:

b = Blog.objects.get(id=1)
b.entry_set.set([e1, e2])

每当是事例中,e1和e2可以是完全的Entry实例,也足以是整数的主键值。

若clear()方法可用,那么以用可迭代对象吃的成员添加到集合中之前,将自entry_set中除去所有曾经在的目标。如果clear()方法不可用,那么将直添加可迭代对象吃的成员如非见面去除所有已在的目标。

这节吃的每个反向操作都以立刻以数据库内推行。所有的加码、创建与去操作为拿马上自动地保留至数据库内。

多对多

大多对准大多关系的两岸都见面活动取访问另一样端的API。这些API的工作方法和前提到的“反往”一对几近干的用法一样。

唯一的别在于属性之名号:定义ManyToManyField的模子使用该字段的性质名称,而“反往”模型使用源模型的稍写名称加上’_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.

与外键字段中一样,在差不多针对大多的字段中吗可以指定related_name名。
(译者注:在一个型中,如果存在多单外键或多对准几近之涉嫌,必须叫他俩分别增长不同的related_name,用于反往查询)

一对一

一定那个相近多对平关联,可以略的经过模型的性访问关联的范。

class EntryDetail(models.Model):
    entry = models.OneToOneField(Entry, on_delete=models.CASCADE)
    details = models.TextField()
#
ed = EntryDetail.objects.get(id=2)
ed.entry # Returns the related Entry object.

不同之处在于反往查询的当儿。一对平涉嫌中之涉模型同样持有一个管理器对象,但是该管理器表示一个纯的靶子要未是目标的集纳:

e = Entry.objects.get(id=2)
e.entrydetail # 返回关联的EntryDetail对象

万一没有对象赋值给此涉及,Django将抛出一个DoesNotExist异常。
得吃反往关系进行赋值,方法以及正向的涉嫌一样:

e.entrydetail = ed
反向关联是怎样促成的?

一些ORM框架需要你以论及之双方都进展定义。Django的开发者认为这违反了DRY
(Don’t Repeat Yourself)原则,所以在Django中你只有待以同一端进行定义。

那么这是怎么落实的吧?因为当事关的模型类没有受加载之前,一个型类向不清楚发生安类与她关系。

答案在app
registry!在Django启动的时段,它会导入所有INSTALLED_APPS中的使及每个应用中之范模块。每创建一个新的模型时,Django会自动抬高反向的涉及有涉的型。如果波及的范还并未导入,Django将保存关联的记录并在干的模子导入时长这些关系。

由于这原因,将模型所在的行使还定义在INSTALLED_APPS的用列表中尽管亮特别重要。否则,反向关联将不可知正确工作。

经关系对象开展询问

论及关联对象的询问和正常值的字段查询仍相同的平整。当您指定询问需要相当的值经常,你可以采用一个对象实例或者目标的主键值。

像,如果您生一个id=5的Blog对象b,下面的老三个查询将是完全一样的:

Entry.objects.filter(blog=b) # 使用对象实例
Entry.objects.filter(blog=b.id) # 使用实例的id
Entry.objects.filter(blog=5) # 直接使用id

3.2.2.10 调用原生SQL语句

万一您意识需要编制的Django查询语句极复杂,你得回归至手工编制SQL语句。Django对于编写原生的SQL查询有许多抉择,参见3.2.6节行原生的SQL查询。

末,需要小心的是Django的数码库层只是一个数据库接口。你可以其他的家伙、编程语言还是数据库框架来做客数据库,Django没有强制指定你免要采取它们的之一功能或模块。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图