乃拼命了邪

迎大家拜我之个人网站《刘江的博客及课程》: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表达式。这对于批量更新同一型中有只字段特别发因此。例如增加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地图