Django模型层---文档笔记

基于对象
反向查询的时候
当你的查询结果可以有多个的时候 就必须加_set.all()
当你的结果只有一个的时候 不需要加_set.all()

模型是你的数据唯一的、权威的信息源。它包含你所储存数据的必要字段和行为。通常,每个模型对应数据库中唯一的一张表。
每个模型都是django.db.models.Model的一个python子类,模型的每个属性都表示数据库中的一个字段。每个字段都被指定成一个类属性,字段名称不要和模型API冲突。Django提供了一套自动生成的用户数据库访问的API。
数据库表的名称是根据模型中的元数据自动生成的,也可以覆写为别的名字。id字段是自动添加的,这个行为也可以被重写。Django会根据设置文件中指定的数据库类型来使用相应的SQL语句。
定义好模型后要使用应用中的模型需要在配置文件的INSTALLED_APPS选项中添加相应的应用名称app.Config/app。添加完应用名,makemigrations生成迁移文件,migrate进行数据库迁移。
模型中每个字段都是Field子类的某个实例。Django根据字段类的类型确认以下信息:
1数据库当中的列类型 (比如, INTEGER , VARCHAR )。
2渲染表单时使用的默认HTML部件(例如,, )。
3最低限度的验证需求,它被用在 Django 管理站点和自动生成的表单中。
Django自带数十种内置的字段类型。你也可以自己编写符合你要求的字段类型。
字段选项(最常用的以下如下)
null:如果为 True ,Django 将用NULL来在数据库中存储空值。默认值是 False.
blank:如果为 True ,该字段允许不填。默认为 False 。
要注意,这与null不同。null纯粹是数据库范畴的,而blank是数据验证范畴的。如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的 blank=False,该字段就是必填的。
choices:由二元组组成的一个可迭代对象,用来为字段提供选择项。如果设置了choices,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices中的选项。二元组中每个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或ModelChoiceField 中用作显示的内容。 在一个给定的 model 类的实例中,想得到某个choices字段的显示值,就调用 get_FOO_display 方法(这里的 FOO 就是choices 字段的名称 )。
default:字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
help_text:表单部件额外显示的帮助内容。即使字段不在表单中使用,它对生成文档也很有用。
primary_key:如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,Django就会自动添加一个IntegerField字段做为主键,除非你想覆盖默认的主键行为,否则没必要设置任何一个字段的 primary_key=True 。主键字段是只读的。如果你在一个已存在的对象上面更改主键的值并且保存,一个新的对象将会在原有对象之外创建出来。
unique:如果该值设置为 True , 这个数据字段的值在整张表中必须是唯一的。
自增主键字段:默认情况下,Django会为每个模型自动添加一个自增主键字段。如果你想指定一个自定义主键字段,只要在某个字段上指定 primary_key=True即可。如果 Django看到你显式地设置了 Field.primary_key ,就不会自动添加id 列。每个模型只能有一个字段指定 primary_key=True (无论是显式声明还是自动添加)。
字段的自述名:除 ForeignKey 、 ManyToManyField 和 OneToOneField 之外,每个字段类型都接受一个可选的位置参数 —— 字段的自述名。如果没有给定自述名,Django将根据字段的属性名称自动创建自述名 —— 将属性名称的下划线替换成空格。ForeignKey、ManyToManyField和OneToOneField都要求第一个参数是一个模型类,所以要使用verbose_name关键字参数才能指定自述名。习惯上,verbose_name 的首字母不用大写。Django在必要的时候会自动大写首字母。
关系:显然,关系数据库的威力体现在表之间的相互关联。Django提供了三种最常见的
数据库关系:多对一(many-to-one),多对多(many-to-many),一对一(one-toone)。
多对一关系:Django使用django.db.models.ForeignKey定义多对一关系。和使用其它字段类型一样:在模型当中把它做为一个类属性包含进来。ForeignKey需要一个位置参数(第一个参数就是该位置参数):与该模型关联的类。建议你用被关联的模型的小写名称做为ForeignKey字段的名字。当然,你也可以起别的名字。
多对多关系:ManyToManyField用来定义多对多关系,用法和其他Field字段类型一样:在模型中做为一个类属性包含进来。ManyToManyField需要一个位置参数(第一个参数就是该位置参数):和该模型关联的类。建议你以被关联模型名称的复数形式做为 ManyToManyField的名字。在哪个模型中设置ManyToManyField并不重要,在两个模型中任选一个即可————————不要两个模型都设置。通常,ManyToManyField实例应该位于可以编辑的表单中。如果要设置更多成员之间关系的细节,Django允许你指定一个模型来定义多对多关系。你可以将其他字段放在中介模型里面。源模型的 ManyToManyField字段将使用through参数指向中介模型。在设置中介模型时,要显式指定外键并关联到多对多关系涉及的模型。这个显式声明定义两个模型之间是如何关联的。
中介模型有一些限制:
1、中介模型必须有且只有一个外键到源模型。或者你必须使用 ManyToManyField.through_fields 显式指定Django应该使用的外键。如果你的模型中存在超个一个的外键,并且 through_fields 没有指定,将会触发一个无效的错误。 对目标模型的外键有相同的限制。
2、对于通过中介模型与自己进行多对多关联的模型,允许存在到同一个模型的两个外键,但它们将被作为多对多关联关系的两个(不同的)方面。如果有超过两个外键,同样你必须像上面一样指定 through_fields ,否则将引发一个验证错误。
3、使用中介模型定义与自身的多对多关系时,你必须设置symmetrical=False。
一对一关系:OneToOneField 用来定义一对一关系。用法和其他字段类型一样:在模型里面做为类属性包含进来。当某个对象想扩展自另一个对象时,最常用的方式就是在这个对象的主键上添加一对一关系。OneToOneField要一个位置参数(第一个参数就是该位置参数):与模型关联的类。一个模型中可以有多个OneToOneField字段。
访问其他应用的模型是非常容易的。 在文件顶部你定义模型的地方,导入相关的模型来实现它。然后,无论在哪里需要的话,都可以引用它。
Django 对字段的命名只有两个限制:

  1. 字段的名称不能是Python保留的关键字,因为这将导致一个Python语法错误。

由于Django 查询语法的工作方式,字段名称中连续的下划线不能超过一个。
这些限制有变通的方法,没有要求字段名称必须与数据库的列名匹配。参考db_column选项。
SQL的保留字例如join、where和select,可以用作模型的字段名,因为Django会对底层的SQL查询语句中的数据库表名和列名进行转义。它根据你的数据库引擎使用不同的引用语法。
元选项:使用内部的class Meta定义模型的元数据。模型元数据是“任何不是字段的数据”。比如排序选项(ordering),数据表名(db_table)或者人类可读的单复数名称( verbose_name和verbose_name_plural)。在模型中添加class Meta是完全可选的,所有选项都不是必须的。
模型最重要的属性是管理器(manager),管理器作用在模型类上而不是模型实例上。
可以在模型上定义自定义的方法来给你的对象添加自定义的“底层”功能。Manager方法用于“表范围”的事务,模型的方法应该着眼于特定的模型实例。
Django中的模型继承与Python中普通类继承方式几乎完全相同,但是模型基本的要求还是要遵守。这表示自定义的模型类应该继承django.db.models.Model。
在Django 中有3中风格的继承。

  1. 通常,你只想使用父类来持有一些信息,你不想在每个子模型中都敲一遍。这个类永远不会单独使用,所以你使用抽象基类。
  2. 如果你继承一个已经存在的模型且想让每个模型具有它自己的数据库表,那么应该使用多表继承。
  3. 最后,如果你只是想改变模块Python 级别的行为,而不用修改模型的字段,你可以使用代理模型。

抽象基类:当你想将一些常见信息存储到很多model的时候,抽象化类是十分有用的。你编写完基类之后,在Meta类中设置abstract=True,该类就不能创建任何数据表。取而代之的是,当它被用来作为一个其他model的基础类时,它将被加入那一子类中。如果抽象化基础类和它的子类有相同的项,那么将会出现error。
元继承:当一个抽象类被创建的时候, Django会自动把你在基类中定义的Meta作为子类的一个属性。如果子类没有声明自己的Meta类, 他将会继承父类的Meta。如果子类想要扩展父类的,可以继承父类的Meta即可。继承时,Django 会对基类的 Meta类做一个调整:在安装 Meta属性之前,Django会设置 abstract=False 。这意味着抽象基类的子类不会自动变成抽象类。 当然,你可以让一个抽象类继承另一个抽象基类,不过每次都要显式地设置abstract=True。
当你在(且仅在)抽象基类中使用 related_name 时,如果想绕过这个问题,名称中就要包含 ‘%(app_label)s’ 和 ‘%(class)s’ 。’%(class)s’ 会替换为子类的小写加下划线格式的名称,字段在子类中使用。’%(app_label)s’ 会替换为应用的小写加下划线格式的名称。
多表继承:这是 Django 支持的第二种继承方式。使用这种继承方式时,同一层级下的每个子model 都是一个真正意义上完整的 model 。 每个子 model 都有专属的数据表,都可以查询和创建数据表。 继承关系在子 model 和它的每个父类之间都添加一个链接 (通过一个自动创建的 OneToOneField 来实现)。
多表继承中的 Meta:在多表继承中,子类继承父类的 Meta类是没什么意义的。所有的 Meta 选项已经对父类起了作用,再次使用只会起反作用。(这与使用抽象基类的情况正好相反,因为抽象基类并没有属于它自己的内容)。所以子model并不能访问它父类的 Meta 类。但是在某些受限的情况下,子类可以从父类继承某些 Meta :如果子类没有指定 ordering 属性或 get_latest_by属性,它就会从父类中继承这些属性。如果父类有了排序设置,而你并不想让子类有任何排序设置,你就可以显式地禁用排序。
代理模型:代理model继承方式要做的:为原始model创建一个代理。你可以创建,删除,更新代理model的实例,而且所有的数据都可以象使用原始model一样被保存。 不同之处在于:你可以在代理model中改变默认的排序设置和默认的manager,更不会对原始model产生影响。声明代理model和声明普通model没有什么不同。设置Meta类中 proxy的值为True,就完成了对代理model的声明。代理 模型必须继承自一个非抽象基类。你不能继承自多个非抽象基类,这是因为一个代理model不能连接不同的数据表。代理model也可以继承任意多个抽象基类,但前提是它们没有定义任何model字段。
代理模型的管理器:如果你没有在代理 模型中定义任何 管理器 ,代理模型就会从父类中继承管理器。如果你在代理模型中定义了一个管理器,它就会变成默认的管理器,不过定义在父类中的管理器仍然有效。
多重继承:就像Python的子类那样,DJango的模型可以继承自多个父类模型。切记一般的Python名称解析规则也会适用。出现特定名称的第一个基类(比如Meta)是所使用的那个。这意味着如果多个父类含有Meta类,只有第一个会被使用,剩下的会忽略掉。一般来说,你并不需要继承多个父类。多重继承主要对“mix-in”类有用:向每个继承mix-in的类添加一个特定的、额外的字段或者方法。你应该尝试将你的继承关系保持得尽可能简洁和直接。
普通的Python类继承允许子类覆盖父类的任何属性。但在Django中,重写Field实例是不允许的(至少现在还不行)。如果基类中有一个author字段,你就不能在子类中创建任何名为author的字段。这些限制仅仅针对做为属性使用的 Field 实例,并不是针对 Python 属性,Python 属性仍是可以被重写的。

------------------------------------------模型字段参考----------------------------------------------
严格意义上来讲,Model是定义在django.db.models.fields里面,但为了使用方便,它们被导入到django.db.models中。

字段选项(Field options)
null:如果为True,Django将空值以NULL存储到数据库中。默认值是False。
字符串字段例如CharField和TextField要避免使用null,因为空字符串值将始终储存为空字符串而不是NULL。如果字符串字段的null=True,那意味着对于“无数据”有两个可能的值:NULL和空字符串。在大多数情况下,对于“无数据”声明两个值是赘余的,Django的惯例是使用空字符串而不是NULL。无论是字符串字段还是非字符串字段,如果你希望在表单中允许空值,你将还需要设置blank=True,因为null仅仅影响数据库存储。
blank:如果为True,则该字段允许为空白。默认值是False。
注意它与null不同。null纯粹是数据库范畴的概念,而blank是数据验证范畴的。如果字段设置blank=True,表单验证时将允许输入空值。如果字段设置blank=False,则该字段为必填。
choices:由二元组组成的一个可迭代对象,用来为字段提供选择项。如果设置了choices,默认的表单将是一个选择框而不是标准的文本框,而且这个选择框的选项就是choices中的选项。二元组中每个元组中的第一个元素,是存储在数据库中的值;第二个元素是在管理界面或ModelChoiceField中用作显示的内容。在一个给定的model类的实例中,想得到某个choices字段的显示值,就调用get_FOO_display 方法(这里的FOO就是choices字段的名称)。一般来说,最好在模型类内部定义choices,然后再给每个值定义一个合适名字的常量。请注意choices可以是任何可迭代的对象–––不是必须是列表或者元组。这一点使你可以动态的构建choices。
db_column:数据库中用来表示该字段的名称。如果未指定,那么Django将会使用Field名作为字段名。
db_index:若值为True, 则django-admin sqlindexes将会为此字段输出
CREATE INDEX语句。(译注:为此字段创建索引)
default:该字段的默认值. 它可以是一个值或者一个可调用对象. 如果是一个可调用对象,那么在每一次创建新对象的时候,它将会调用一次。请注意 lambda函数不可作为如 default 这类可选参数的值.因为它们无法被migrations命令序列化。
editable:如果设为False, 这个字段将不会出现在admin或者其他ModelForm.他们也会跳过模型验证.默认是True .
error_messages:能够让你重写默认抛出的错误信息。通过指定key来确认你要重写的错误信息。error_messages的key值包括null,blank,invalid,unique, 和 unique_for_date,invalid_choice. 其余的error_messages的keys是不一样的在不同的章节下Field types。
help_text:额外的 ‘help’ 文本将被显示在表单控件form中。即便你的字段没有应用到一个form里面,这样的操作对文档化也很有帮助。注意这不会自动添加HTML标签。需要你在help_text包含自己需要的格式。
primary_key:若为True,则该字段会成为模型的主键字段。如果你没有在模型的任何字段上指定primary_key=True,Django会自动添加一个AutoField字段来充当键。所以除非你想要覆盖默认的主键行为,否则不需要在任何字段上设定primary_key=True。primary_key=True暗含着null=False和unique=True. 一个对象上只能拥有一个主键.主键字段是只读的。如果你改变了一个已存在对象上的主键并且保存的话,会创建一个新的对象,而不是覆盖旧的.
unique:如果为True,这个字段在表中必须有唯一值。这是一个在数据库级别的强制性动作,并且通过模型来验证。除了 ManyToManyField、OneToOneField和 FileField以外的其他字段类型都可以使用这个设置。注意当设置unique为True时,你不需要再指定db_index,因为unique本身就意味着一个索引的创建。
unique_for_date:当设置它为DateField和DateTimeField字段的名称时,表示要求该字段对于相应的日期字段值是唯一的。这是在模型验证期间通过Model.validate_unique() 强制执行的,而不是在数据库层级进行验证。
unique_for_month/unique_for_year
verbose_name:一个字段的可读性更高的名称。如果用户没有设定冗余名称字段,Django会自动将该字段属性名中的下划线转换为空格,并用它来创建冗余名称。
validators:该字段将要运行的一个Validator的列表。

自增字段AutoField:一个根据实际ID自动增长的IntegerField。你通常不需要直接使用;如果不指定,一个主键字段将自动添加到你创建的模型中。
BigIntegerField:一个64位整数,这个字段默认的表单组件是一个TextInput。
BinaryField:这是一个用来存储原始二进制码的Field. 只支持 bytes 赋值,注意这个Field只有很有限的功能。
BooleanField:true/false字段。此字段的默认表单挂件是一个CheckboxInput。
如果你需要设置null值,则使用NullBooleanField来代替BooleanField。如果 Field.default没有指定的话,BooleanField的默认值是None。
CharField:一个用来存储从小到很大各种长度的字符串的地方如果是巨大的文本类型, 可以用 TextField .这个字段默认的表单样式是 TextInput .CharField 必须接收一个额外的参数:CharField.max_length字段的最大字符长度.max_length将在数据库层和Django表单验证中起作用, 用来限定字段的长度。
CommaSeparatedIntegerField:一个逗号分隔的整数字段。像 CharField 一样, 需要一个 max_length 参数,同时数据库移植时也需要注意。
DateField:这是一个使用Python的 datetime.date 实例表示的日期,该字段默认对应的表单控件是一个 TextInput。有几个额外的设置参数:DateField.auto_now:每次保存对象时,自动设置该字段为当前时间。用于"最后一次修改"的时间戳。DateField.auto_now_add:当对象第一次被创建时自动设置当前时间。用于创建时间的时间戳. 它总是使用当前日期。auto_now_add , auto_now , and default 这些设置是相互排斥的. 他们之间的任何组合将会发生错误的结果.在目前的实现中,设置 auto_now或者auto_now_add为True将为让这个字段同时得到editable=False和 blank=True这两个设置。
DateTimeField:它是通过Python datetime.datetime 实例表示的日期和时间. 携带了跟DateField一样的额外参数。(TextInput)
DecimalField:用python中 Decimal 的一个实例来表示十进制浮点数. 有两个必须的参数:DecimalField.max_digits位数总数,包括小数点后的位数。该值必须大于等于decimal_places。DecimalField.decimal_places小数点后的数字数量。(TextInput)
DurationField:用作存储一段时间的字段类型 - 类似Python中的timedelta。
EmailField:一个CharField用来检查输入的email地址是否合法。它使用EmailValidator来验证输入合法性。默认最大长度max_length从75增加到254以符合RFC3696/5321标准。
FileField(ClearableFileInput):一个上传文件的字段。FileField字段不支持primary_key和unique参数。有两个可选参数:FileField.upload_to:一个本地文件系统的路径,它将附加到MEDIA_ROOT设置的后面来确定url属性的值。它还可以是一个可调用对象如函数,将调用它来获取上传路径,包括文件名。这个路径可能会包含一个 strftime() 格式串,并且会在文件上传时被替换为 实际的date/time作为文件路径。
FileField.storage:一个Storage对象,用于你的文件的存取。
在模型中调用FileField或ImageField(见下方)需如下几步:

  1. 在你的settings文件中, 你必须要定义 MEDIA_ROOT 作为Django存储上传文件
    的路径(从性能上考虑,这些文件不能存在数据库中。) 定义一个 MEDIA_URL作为基础的URL或者目录。确保这个目录可以被web server使用的账户写入。
  2. 在模型中添加 FileField 或 ImageField 字段, 定义upload_to参数,内容是 MEDIA_ROOT 的子目录,用来存放上传的文件。
  3. 数据库中存放的仅是这个文件的路径(相对于MEDIA_ROOT). 你很可能会想用由Django提供的便利的 url 属性。比如说, 如果你的 ImageField 命名为mug_shot , 你可以在template中用 ``获得你照片的绝对路径。
    上传的文件对应的URL可以通过使用 url 属性获得. 在内部,它会调用Storage 类下的 url() 方法.

FileField max_length默认长度为100。
FieldFile:当你添加FileField到你的模型中时, 你实际上会获得一个FieldFile 的实例来替代将要访问的文件。 除了继承至 django.core.files.File 的功能外, 这个类还有其他属性和方法可以用于访问文件。
FieldFile.url:通过潜在 Storage 类的 url() 方法可以只读地访问文件的URL。
FieldFile.open:该方法像标准的Python open()方法,并可通过mode参数设置打开模式.
FieldFile.close:该方法像标准的Python file.close() 方法,并关闭相关文件.
FieldFile.save:这个方法会将文件名以及文件内容传递到字段的storage类中,并将模型字段与保存好的文件关联.
FieldFile.delete:删除与此实例关联的文件,并清除该字段的所有属性。注意︰ 如果它碰巧是开放的调用 delete() 方法 时,此方法将关闭该文件。注意,model删除的时候,与之关联的文件并不会被删除。如果你要把文件也清理掉,你需要自己处理。
FilePathField:一个CharField,内容只限于文件系统内特定目录下的文件名。有三个参数, 其中第一个是 必需的:FilePathField.path。max_length=100。
FloatField:用Python的一个 float 实例来表示一个浮点数.(TextInput)
ImageField:继承了FileField的所有属性和方法, 但还对上传的对象进行校验,确保它是个有效的image.除了从FileField继承来的属性外,ImageField还有宽和高属性。ImageField字段需要调用Pillow库.(ClearableFileInput)
IntegerField:一个整数。(TextInput)
IPAddressField:废弃
GenericIPAddressField(TextInput):一个IPv4或IPv6地址, 字符串格式。
NullBooleanField:类似 BooleanField , 但是允许 NULL 作为一个选项.(NullBooleanSelect)
PositiveIntegerField:类似IntegerField,但值必须是正数或者零(0).
PositiveSmallIntegerField:该模型字段类似 PositiveIntegerField , 但是只允许小于某一特定值。(0-32767)
SmallIntegerField
TextField:大文本字段。该模型默认的表单组件是Textarea。
TimeField:时间字段,和Python中 datetime.time 一样。接受与 DateField 相同的自动填充选项。(TextInput)
URLField:一个CharField类型的URL此字段的默认表单widget为TextInput。
UUIDField:一个用来存储UUID的字段。使用Python的 UUID 类。

关系字段

ForeignKey:多对一关系。需要一个位置参数:与该模型关联的类。若要创建一个递归的关联 —— 对象与自己具有多对一的关系 —— 请使用 models.ForeignKey(‘self’) 。如果你需要关联到一个还没有定义的模型,你可以使用模型的名字而不用模型对象本身。若要引用在其它应用中定义的模型,你可以用带有完整标签名的模型来显式指定。ForeignKey 会自动创建数据库索引。在幕后,Django 会在字段名上添加 “_id” 来创建数据库中的列名。

ForeignKey.limit_choices_to:

ForeignKey.related_name:这个名称用于让关联的对象反查到源对象。它还是 related_query_name 的默认值(关联的模型进行反向过滤时使用的名称)。注意,当你为抽象模型定义关联关系的时,必须设置这个参数的值;而且当你这么做的时候需要用到一些特殊语法。如果你不想让Django 创建一个反向关联,请设置 related_name 为 ‘+’ 或者以 ‘+’ 结尾。ForeignKey.related_query_name:这个名称用于目标模型的反向过滤。如果设置了 related_name ,则默认为它的值,否则默认值为模型的名称。

ForeignKey.to_field:关联到的关联对象的字段名称。默认地,Django 使用关联对象的主键。

ForeignKey.db_constraint:控制是否在数据库中为这个外键创建约束。默认值为 True。如果被设置成 False ,访问一个不存在的关联对象将抛出 DoesNotExist 异常。

ForeignKey.on_delete:当一个 ForeignKey 引用的对象被删除时,Django 默认模拟SQL的 ON DELETE CASCADE 的约束行为,并且删除包含该 ForeignKey 的对象。这种行为可以通过设置 on_delete 参数来改变。

on_delete 在 django.db.models 中可以找到的值有:

CASCADE:级联删除;默认值。

PROTECT:抛出 ProtectedError 以阻止被引用对象的删除,它是 django.db.IntegrityError 的一个子类。

SET_NULL:把 ForeignKey 设置为null; null 参数为 True 时才可以这样做。

SET_DEFAULT:ForeignKey 值设置成它的默认值;此时必须设置 ForeignKey 的default参数。

SET ():设置ForeignKey为传递给SET()的值,如果传递的是一个可调用对象,则为调用后的结果。

DO_NOTHING:不采取任何动作。

ManyToManyField:一个多对多关联。要求一个关键字参数:与该模型关联的类,与 ForeignKey 的工作方式完全一样,包括递归关系 和惰性关系。关联的对象可以通过字段的 RelatedManager 添加、删除和创建。

数据库中的表示在幕后,Django 创建一个中间表来表示多对多关系。默认情况下,这张中间表的名称使用多对多字段的名称和包含这张表的模型的名称生成。你可以使用 db_table 选项手工提供中间表的名称。

ManyToManyField.related_name与 ForeignKey.related_name 相同。ManyToManyField.related_query_name与 ForeignKey.related_query_name 相同。ManyToManyField.limit_choices_to与 ForeignKey.limit_choices_to 相同。limit_choices_to 对于使用 through 参数自定义中间表的 ManyToManyField 不生效。

ManyToManyField.symmetrical只用于与自身进行关联的ManyToManyField。如果你希望与 self 进行多对多关联的关系不具有对称性,可以设置 symmetrical 为 False 。这会强制让Django 添加一个描述器给反向的关联关系,以使得 ManyToManyField 的关联关系不是对称的。ManyToManyField.through:Django 会自动创建一个表来管理多对多关系。不过,如果你希望手动指定中介表,可以使用 through 选项来指定Django 模型来表示你想要使用的中介表。这个选项最常见的使用场景是当你想要关联额外的数据到多对多关联关系的时候。

如果 ManyToManyField 的源模型和目标模型相同,则生成以下字段:

id :关系的主键。
from_<model>_id :源模型实例的 id 。
to_<model>_id :目标模型实例的 id 。

ManyToManyField.through_fields:through_fields 接收一个二元组 (‘field1’, ‘field2’) ,其中 field1 为指向定义 ManyToManyField 字段的模型的外键名称, field2 为指向目标模型的外键的名称。当中间模型具有多个外键指向多对多关联关系模型中的任何一个(或两个),你必须 指定 through_fields 。

ManyToManyField.db_table:为存储多对多数据而创建的表的名称。如果没有提供,Django 将基于定义关联关系的模型和字段假设一个默认的名称。

ManyToManyField.db_constraint:控制中间表中的外键是否创建约束。默认为 True。不可以同时传递 db_constraint 和 through 。 ManyToManyField.swappable

OneToOneField:一对一关联关系。概念上讲,这个字段很像是 ForeignKey 设置了 unique=True ,不同的是它会直接返回关系另一边的单个对象。它最主要的用途是作为扩展自另外一个模型的主键;例如,多表继承就是通过对子模型添加一个隐式的一对一关联关系到父模型实现的。需要一个位置参数:与该模型关联的类。 它的工作方式与 ForeignKey 完全一致,包括所有与递归关系和惰性关系相关的选项。如果你没有指定 OneToOneField 的 related_name 参数,Django 将使用当前模型的小写的名称作为默认值。

OneToOneField.parent_link:当它为 True 并在继承自另一个具体模型 的模型中使用时,表示该字段应该用于反查的父类的链接,而不是在子类化时隐式创建的 OneToOneField 。

Field API 参考(比较难于理解,后期还要参考文档进行深入了解)

Field 是一个抽象的类, 用来代表数据库中的表的一列。Django 使用这些fields 去创建表 ( db_type() ), 去建立Python中的类型和数据库中类型的映射关系( get_prep_value() ) 反之亦然 ( from_db_value() ), 并且实现Lookup API reference ( get_prep_lookup() ).field 是不同Django版本API中最根本的部分,尤其是 models and querysets 。在模型中,一个字段被实例化为类的属性,并表现为一个特定的表的列。它具有 null 和 唯一 等属性,以及Django用于将字段值映射到数据库特定值的方法。字段 是 RegisterLookupMixin 的子类,因此可以在其上注册 Transform 和 Lookup。

有三种主要情况,Django需要与数据库后端和字段交互:

当它查询数据库(Python值 转为 数据库后端值)

当它从数据库加载数据(数据库后端值 转为 Python值)

当它保存到数据库(Python值 转为 数据库后端值)

查询时,使用 get_db_prep_value() 和 get_prep_value()。

加载数据时,使用 from_db_value()。

保存时,使用 pre_save() 和 get_db_prep_save()。

模型元选项

abstract:如果 abstract = True, 就表示模型是 抽象基类 (abstract base class).

app_label:如果你的模型定义在默认的models.py之外,你必须告诉Django该模型属于哪个应用。

Django 1.7中新增:一个应用中,定义在models 模块以外的模型,不再需要app_label。

db_table:该模型所用的数据表的名称。

db_tablespace:当前模型所使用的数据库表空间 的名字。默认值是项目设置中的DEFAULT_TABLESPACE,如果它存在的话。如果后端并不支持表空间,这个选项可以忽略。default_related_name:这个名字会默认被用于一个关联对象到当前对象的关系。默认为 _set。由于一个字段的反转名称应该是唯一的,当你给你的模型设计子类时,要格外小心。为了规避名称冲突,名称的一部分应该含有’%(app_label)s’和’%(model_name)s’,它们会被应用标签的名称和模型的名称替换,二者都是小写的。

get_latest_by:模型中某个可排序的字段的名称。它指定了Manager的latest()和earliest()中使用的默认字段。

managed:默认为True。

order_with_respect_to:按照给定的字段把这个对象标记为”可排序的“。当order_with_respect_to 设置之后,模型会提供两个用于设置和获取关联对象顺序的方法:get_RELATED_order()和set_RELATED_order(),其中RELATED是小写的模型名称。相关联的对象也有两个方法,get_next_in_order() 和get_previous_in_order(),用于按照合适的顺序访问它们。order_with_respect_to属性会添加一个额外的字段(数据表中的列)叫做_order,所以如果你在首次迁移之后添加或修改了order_with_respect_to属性,要确保执行和应用了合适的迁移操作。

ordering:对象默认的顺序,获取一个对象的列表时使用。它是一个字符串的列表或元组。每个字符串是一个字段名,前面带有可选的“-”前缀表示倒序。前面没有“-”的字段表示正序。使用"?"来表示随机排序。

proxy:如果proxy = True, 作为该模型子类的另一个模型会被视为代理模型。

select_on_save:该选项决定了Django是否采用1.6之前的 django.db.models.Model.save()算法。旧的算法使用SELECT来判断是否存在需要更新的行。而新式的算法直接尝试使用UPDATE。

unique_together:用来设置的不重复的字段组合。组合起来的时候必须是唯一的。

index_together:用来设置带有索引的字段组合。

verbose_name:对象的一个易于理解的名称,为单数。如果此项没有设置,Django会把类名拆分开来作为自述名。verbose_name_plural:该对象复数形式的名称。如果此项没有设置,Django 会使用 verbose_name + “s”。

----------------------------查询集-------------------------------

一旦你建立好数据模型之后,django会自动生成一套数据库抽象的API,可以让你执行增删改查的操作。为了把数据库表中的数据表示成python对象,django使用一种直观的方式:一个模型类代表数据库的一个表,一个模型的实例代表数据库表中的一条特定的记录。

在你显式调用save()之前,django不会访问数据库。save()方法没有返回值。如果你想只用一条语句创建并保存一个对象,使用create()方法。调用save()方法,来保存已经存在于数据库中的对象的改动。已存在对象的更改背后执行了sql的UPDATE操作。在你显式调用save()之前,django不会访问数据库。

更新ForeignKey字段的方式和保存普通字段相同–只是简单地把一个类型正确的对象赋值到字段中。

更新ManyToManyField的方式有一些不同–使用字段的add()方法来增加关系的记录。为了在一条语句中,向ManyToManyField添加多条记录,可以在调用add()方法时传入多个参数。

获取对象:通过模型中的Manager构造一个QuertSet,来从你的数据库中获取对象。QuerySet表示你数据库中取出来的一个对象的集合。它可以含有零个、一个或者多个过滤器,过滤器根据所给的参数限制查询结果的范围。在sql的角度,QuerySet和SELECT命令等价,过滤器是像WHERE和LIMIT一样的限制子句。每个模型都至少有一个Manager,它通常命名为objects。通过模型类直接访问它。管理器通常只可以通过模型类来访问,不可以通过模型实例来访问。这是为了强制区分表级别和记录级别的操作。对于一个模型来说,Manager是QuerySet的主要来源。

获取一个表中所有对象的最简单的方式是全部获取。使用Manager的all()方法。

all()方法返回包含数据库中所有对象的QuerySet。

filter(**kwargs) 返回一个包含对象的集合,它们满足参数中所给的条件。

exclude(**kwargs) 返回一个包含对象的集合,它们不满足参数中所给的条件。

链式过滤:QuerySet的精炼结果还是QuerySet,所以你可以把精炼用的语句组合到一起。

过滤后的结果集是独立的:每次你筛选一个结果集,得到的都是全新的另一个结果集,它和之前的结果集之间没有任何绑定关系。每次筛选都会创建一个独立的结果集,可以被存储及反复使用。

查询集是延迟的:QuerySets 是惰性的 – 创建 QuerySet 的动作不涉及任何数据库操作。你可以一直添加过滤器,在这个过程中,Django 不会执行任何数据库查询,除非 QuerySet 被执行.一般情况下, QuerySet 不能从数据库中主动地获得数据,得被动地由你来请求。对 QuerySet 求值就意味着 Django 会访问数据库。

限制查询集范围:可以用 python 的数组切片语法来限制你的 QuerySet 以得到一部分结果。它等价于SQL中的 LIMIT 和 OFFSET 。Django 不支持对查询集做负数索引。一般来说,对 QuerySet 切片会返回新的 QuerySet – 这个过程中不会对运行查询。不过也有例外,如果你在切片时使用了 “step” 参数,查询集就会被求值,就在数据库中运行查询。要检索单独的对象,而非列表 (比如 SELECT foo FROM bar LIMIT 1),可以直接使用索引来代替切片。

字段筛选条件:字段筛选条件就是 SQL 语句中的 WHERE 从句。就是 Django 中的 QuerySet 的filter(), exclude() 和 get() 方法中的关键字参数。筛选条件的形式是 field__lookuptype=value 。 (注意:这里是双下划线)。数据库 API 支持24种查询类型。如果你没有提供查询类型 – 也就是说关键字参数中没有双下划线,那么查询类型就会被指定为 exact。

跨关系查询:Django 提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的 model 为止。跨关系的筛选条件可以一直延展。关系也是可逆的。可以在目标 model 上使用源 model 名称的小写形式得到反向关联。如果在某个关联 model 中找不到符合过滤条件的对象,Django 将视它为一个空的(所有的值都是 NULL), 但是可用的对象。这意味着不会有异常抛出。对于包含在同一个 filter() 中的筛选条件,查询集要同时满足所有筛选条件。而对于连续的filter() ,查询集的范围是依次限定的。

F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。你也可以在 F() 对象中使用两个下划线做跨关系查询。F() 对象使用两个下划线引入必要的关联对象。

主键查询的简捷方式:为使用方便考虑,Django 用 pk 代表主键"primary key"。pk 对 __exact 查询同样有效,任何查询项都可以用 pk 来构造基于主键的查询。pk 查询也可以跨关系。

在LIKE语句中转义百分号%和下划线_:字段筛选条件相当于 LIKE SQL 语句 (iexact, contains, icontains, startswith,istartswith, endswith 和 iendswith) ,它会自动转义两个特殊符号 – 百分号%和下划线。(在 LIKE 语句中,百分号%表示多字符匹配,而下划线表示单字符匹配。)这就意味着我们可以直接使用这两个字符,而不用考虑他们的 SQL 语义。下划线_和百分号%的处理方式相同,Django 都会自动转义。

缓存和查询:每个 QuerySet 都包含一个缓存,以减少对数据库的访问。要编写高效代码,就要理解缓存是如何工作的。一个 QuerySet 时刚刚创建的时候,缓存是空的。 QuerySet 第一次运行时,会执行数据库查询,接下来 Django 就在 QuerySet 的缓存中保存查询的结果,并根据请求返回这些结果(比如,后面再次调用这个 QuerySet 的时候)。再次运行QuerySet 时就会重用这些缓存结果。

用 Q 对象实现复杂查找 (Complex lookups with Q objects):在 filter() 等函式中关键字参数彼此之间都是 “AND” 关系。如果你要执行更复杂的查询(比如,实现筛选条件的 OR 关系),可以使用 Q 对象。Q 对象(django.db.models.Q)是用来封装一组查询关键字的对象。Q 对象可以用 & 和 | 运算符进行连接。当某个操作连接两个 Q 对象时,就会产生一个新的等价的 Q 对象。你可以用 & 和 | 连接任意多的 Q 对象,而且可以用括号分组。Q 对象也可以用 ~操作取反,而且普通查询和取反查询(NOT)可以连接在一起使用。每种查询函式(比如 filter(), exclude(), get()) 除了能接收关键字参数以外,也能以位置参数的形式接受一个或多个 Q 对象。如果你给查询函式传递了多个 Q 对象,那么它们彼此间都是 “AND” 关系。查找函式可以混用 Q 对象和关键字参数。查询函式的所有参数(Q 关系和关键字参数) 都是 “AND” 关系。但是,如果参数中有 Q 对象,它必须排在所有的关键字参数之前。

对象比较:要比较两个对象,就和 Python 一样,使用双等号运算符:==。实际上比较的是两个 model 的主键值。如果 model 的主键名称不是 id,也没关系。Django 会自动比较主键的值,而不管他们的名称是什么。

对象删除:删除方法就是 delete()。它运行时立即删除对象而不返回任何值。你也可以一次性删除多个对象。每个 QuerySet 都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象。要牢记这一点:无论在什么情况下,QuerySet 中的 delete() 方法都只使用一条SQL 语句一次性删除所有对象,而并不是分别删除每个对象。如果你想使用在model 中自定义的 delete() 方法,就要自行调用每个对象的delete 方法。(例如,遍历 QuerySet,在每个对象上调用 delete()方法),而不是使用 QuerySet 中的delete()方法。在 Django 删除对象时,会模仿 SQL 约束 ON DELETE CASCADE 的行为,换句话说,删除一个对象时也会删除与它相关联的外键对象。要注意的是: delete() 方法是 QuerySet 上的方法,但并不适用于 Manager 本身。这是一种保护机制,是为了避免意外地调用 Entry.objects.delete() 方法导致 所有的记录被误删除。如果你确认要删除所有的对象,那么你必须显式地调用: Model.objects.all().delete()。

一次更新多个对象:对 QuerySet 中的所有对象,一次更新某个字段的值。这个要求可以用 update() 方法完成。这种方法仅适用于非关系字段和 ForeignKey 外键字段。更新非关系字段时,传入的值应该是一个常量。更新 ForeignKey 字段时,传入的值应该是你想关联的那个类的某个实例。update() 方法也是即时生效,不返回任何值。在 QuerySet 进行更新时,唯一的限制就是一次只能更新一个数据表,就是当前 model 的主表。所以不要尝试更新关联表和与此类似的操作,因为这是不可能运行的。要小心的是: update() 方法是直接翻译成一条 SQL 语句的。因此它是直接地一次完成所有更新。它不会调用你的 model 中的 save() 方法,也不会发出pre_save 和post_save 信号(这些信号在调用 save() 方法时产生)。在调用 update 时可以使用 F()对象 来把某个字段的值更新为另一个字段的值。这对于自增记数器是非常有用的。

对象关联:当你定义在 model 定义关系时 (例如, ForeignKey, OneToOneField, 或ManyToManyField),model 的实例自带一套很方便的API以获取关联的对象。Django 也提供反向获取关联对象的 API,就是由从被关联的对象得到其定义关系的主对象。

一对多关系

正向关联:如果一个 model 有一个 ForeignKey字段,我们只要通过使用关联 model 的名称就可以得到相关联的外键对象。你可以设置和获得外键属性。正如你所期望的,改变外键的行为并不引发数据库操作,直到你调用 save()方法时,才会保存到数据库。在一对多关系中,第一次正向获取关联对象时,关联对象会被缓存。其后根据外键访问时这个实例,就会从缓存中获得它。要注意的是,QuerySet 的 select_related() 方法提前将所有的一对多关系放入缓存中。

逆向关联:如果 model 有一个 ForeignKey外键字段,**那么外联 model 的实例可以通过访问Manager 来得到所有相关联的源 model 的实例。默认情况下,这个 Manager 被命名为 FOO_set, 这里面的 FOO 就是源 model 的小写名称。**这个 Manager 返回QuerySets,它是可过滤和可操作的。你可以通过在 ForeignKey() 的定义中设置 related_name 的值来覆写 FOO_set 的名称。你不能在一个类当中访问 ForeignKey Manager ;而必须通过类的实例来访问。ForeignKey Manager中的方法(create,add,remove,clear)很多都是实时操作数据库的,每一个添加,创建,删除操作都会及时保存将结果保存到数据库中。

多对多关系

在多对多关系的任何一方都可以使用 API 访问相关联的另一方。多对多的 API 用起来和上面提到的 “逆向” 一对多关系关系非常相象。唯一的差别就在于属性的命名: ManyToManyField 所在的 model (为了方便,我称之为源model A) 使用字段本身的名称来访问关联对象;而被关联的另一方则使用 A的小写名称加上 ‘_set’ 后缀(这与逆向的一对多关系非常相象)。与 ForeignKey 一样, ManyToManyField 也可以指定 related_name。

一对一关系

相对于多对一关系而言,一对一关系不是非常简单的。如果你在 model 中定义了一个 OneToOneField 关系,那么你就可以用这个字段的名称做为属性来访问其所关联的对象。与 “reverse” 查询不同的是,一对一关系的关联对象也可以访问 Manager 对象,但是这个 Manager 表现一个单独的对象,而不是一个列表。和你定义正向关联所用的方式一样,类的实例也可以赋予逆向关联方。

关系中的反向连接是如何做到的?

其他对象关系的映射(ORM)需要你在关联双方都定义关系。而 Django 的开发者则认为这违背了 DRY 原则 (Don’t Repeat Yourself),所以 Django 只需要你在一方定义关系即可。但仅由一个 model 类并不能知道其他 model 类是如何与它关联的,除非是其他model 也被载入,那么这是如何办到的?答案就在于 INSTALLED_APPS 设置中。任何一个 model 在第一次调用时,Django 就会遍历所有的 INSTALLED_APPS 的所有 models,并且在内存中创建必要的反向连接。本质上来说,INSTALLED_APPS 的作用之一就是确认 Django完整的 model 范围。

在关联对象上的查询

包含关联对象的查询与包含普通字段值的查询都遵循相同的规则。为某个查询指定某个值的时候,你可以使用一个类实例,也可以使用对象的主键值。

直接使用SQL

如果你发现某个 SQL 查询用 Django 的数据库映射来处理会非常复杂的话,你可以使用直接写 SQL 来完成。建议的方式是在你的 model 自定义方法或是自定义 model 的 manager 方法来运行查询。虽然 Django 不要求数据操作必须在 model 层中执行。但是把你的商业逻辑代码放在一个地方,从代码组织的角度来看,也是十分明智的。

--------------------------------------QuerySet API参考-------------------------------------------

在内部,可以创建、过滤、切片和传递 查询集 而不用真实操作数据库。在你对查询集做求值之前,不会发生任何实际的数据库操作。

可以使用下列方法对查询集求值:
  • 迭代。 queryset 是可迭代的,它在首次迭代查询集时执行实际的数据库查询。
  • 切片。 正如在限制查询集中解释的那样, 可以使用Python 的序列切片语法对一个 查询集 进行分片。一个未求值的 查询集 进行切片通常返回另一个未求值的 查询集 ,但是如果你使用切片的”step“参数,Django将执行数据库查询并返回一个列表。对一个已经求值的查询集进行切片将返回一个列表。还要注意,虽然对未求值的 查询集 进行切片返回另一个未求值的 查询集 ,但是却不可以进一步修改它了(例如,添加更多的Filter,或者修改排序的方式),因为这将不太好翻译成SQL而且含义也不清晰。
  • 序列化/缓存。
  • repr()。 当对 查询集 调用 repr() 时,将对它求值。
  • len()。 当你对 查询集 调用 len() 时,将对它求值。Django 提供了一个count()方法更高效。
  • list()。 对 查询集 调用 list() 将强制对它求值。
  • bool()。 测试一个 查询集 的布尔值,例如使用 bool() 、 or 、 and 或者 if 语句将导致查询集的执行。如果至少有一个记录,则 查询集 为 True ,否则为 False 。

注:如果你需要知道是否存在至少一条记录(而不需要真实的对象),使用exists() 将更加高效。

Pickle 查询集:如果你 Pickle 一个查询集 ,它将在Pickle之前强制将所有的结果加载到内存中。这意味着当你Unpickle 查询集 时,它包含Pickle 时的结果,而不是当前数据库中的结果。查询集 的Pickle 只能用于生成它们的Django 版本中。如果你使用Django 的版本N生成一个Pickle,不保证这个Pickle 在Django 的版本N+1 中可以读取。Pickle 不可用于归档的长期策略。

查询集 API

QuerySet 类具有两个公有属性用于内省:

  • ordered:如果 QuerySet 是排好序的则为 True。
  • db:使用的数据库。

Django 提供了一系列的QuerySet筛选方法,用于改变QuerySet返回的结果类型或者SQL查询执行的方式。

返回QuerySets的方法

filter:返回一个新的QuerySet,包含与给定的查询参数匹配的对象。

exclude:返回一个新的 QuerySet ,它包含不满足给定的查找参数的对象。

annotate:关键字参数指定的Annotation 将使用关键字作为Annotation 的别名。匿名的参数的别名将基于聚合函数的名称和模型的字段生成。只有引用单个字段的聚合表达式才可以使用匿名参数。其它所有形式都必须用关键字参数。

order_by:默认情况下, QuerySet 根据模型 Meta 类的 ordering 选项排序。你可以使用 order_by 方法给每个 QuerySet 指定特定的排序。如果排序的字段与另外一个模型关联,Django 将使用关联的模型的默认排序,或者如果没有指定 Meta.ordering 将通过关联的模型的主键排序。

reverse:反向排序QuerySet 中返回的元素。如果 QuerySet 没有定义排序,调用 reverse() 将不会有任何效果。

distinct:返回一个在SQL 查询中使用 SELECT DISTINCT 的新 QuerySet 。它将去除查询结果中重复的行。默认情况下, QuerySet 不会去除重复的行。

values:返回一个 ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。每个字典表示一个对象,键对应于模型对象的属性名称。values() 接收可选的位置参数 *fields ,它指定 SELECT 应该限制哪些字段。如果指定字段,每个字典将只包含指定的字段的键/值。如果没有指定字段,每个字典将包含数据库表中所有字段的键和值。

values_list:与 values() 类似,只是在迭代时返回的是元组而不是字典。每个元组包含传递给 values_list() 调用的字段的值。如果只传递一个字段,你还可以传递 flat 参数。如果为 True ,它表示返回的结果为单个值而不是元组。如果你不传递任何值给 values_list() ,它将返回模型中的所有字段,以它们在模型中定义的顺序。这个方法返回 ValuesListQuerySet 。这个类的行为类似列表。大部分时候它足够用了,但是如果你需要一个真实的Python 列表对象,可以对它调用 list() ,这将会对查询集求值。

dates:返回 DateQuerySet - QuerySet ,其计算结果为 datetime.date 对象列表,表示特定种类的所有可用日期 QuerySet 。field 应为模型的 DateField 的名称。 kind 应为 “year” 、 “month” 或 “day” 。

datetimes:返回 QuerySet ,其计算为 datetime.datetime 对象的列表,表示 QuerySet 内容中特定种类的所有可用日期。field_name 应为模型的 DateTimeField 的名称。kind 应为 “year” , “month” , “day” , “hour” , “分钟” 或 “秒” 。

none:调用none()将创建一个从不返回任何对象的查询集,并且在访问结果时不会执行任何查询。qs.none()查询集是 EmptyQuerySet 的一个实例。

all:返回当前 QuerySet (或 QuerySet 子类) 的副本。当对 QuerySet 进行求值时,它通常会缓存其结果。如果数据库中的数据在 QuerySet 求值之后可能已经改变,你可以通过在以前求值过的 QuerySet 上调用相同的 all() 查询以获得更新后的结果。

select_related:返回一个 QuerySet ,当执行它的查询时它沿着外键关系查询关联的对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。在传递给 select_related() 的字段中,你可以使用任何 ForeignKey和 OneToOneField 。在传递给 select_related 的字段中,你还可以反向引用 OneToOneField ——也就是说,你可以回溯到定义 OneToOneField 的字段。此时,可以使用关联对象字段的 related_name ,而不要指定字段的名称。如果你需要清除 QuerySet 上以前的 select_related 添加的关联字段,可以传递一个 None 作为参数: a = queryset.select_related(None)

prefetch_related(太过复杂,没看懂,回头再看):返回 QuerySet ,它将在单个批处理中自动检索每个指定查找的相关对象。

extra(内容过多也需要重新看):Django 提供了 extra() QuerySet 修改机制 — 它能在 QuerySet 生成的SQL从句中注入新子句。extra可以指定一个或多个 参数 ,例如 select , where or tables . 这些参数都不是必须的,但是你至少要使用一个。

defer:如果您在某些情况下使用查询集的结果,当您最初获取数据时不知道是否需要这些特定字段,可以告诉Django不要从数据库中检索它们。这是通过传递字段名称不加载到 defer()。具有延迟字段的查询集仍将返回模型实例。如果您访问该字段(一次一个,而不是一次所有的延迟字段),将从数据库中检索每个延迟字段。您可以多次调用 defer() 。每个调用都向延迟集添加新字段。字段添加到延迟集的顺序无关紧要。调用具有已延迟的字段名称的 defer() 是无害的(该字段仍将被延迟)。您可以使用标准的双下划线符号来分隔相关字段,从而推迟相关模型中的字段加载。如果要清除延迟字段集,请将 None 作为参数传递到 defer()。模型中的某些字段不会被延迟,即使您要求它们。你永远不能推迟加载主键。如果您使用 select_related() 检索相关模型,则不应推迟从主模型连接到相关模型的字段的加载,否则将导致错误。当对具有延迟字段的实例调用 save() 时,仅保存加载的字段。

only:only() 方法或多或少与 defer() 相反。只对only中指定的字段进行立即加载,其余的都被推迟。

using:如果你使用多个数据库,这个方法用于控制 QuerySet 将在哪个数据库上求值。这个方法的唯一参数是数据库的别名,定义在 DATABASES 。

select_for_update:返回一个 queryset ,会锁定相关行直到事务结束。

raw:raw 移动到 QuerySet 类中。以前,它只位于 Manager 中。接收一个原始的SQL 查询,执行它并返回一个 django.db.models.query.RawQuerySet 实例。这个 RawQuerySet 实例可以迭代以提供实例对象,就像普通的 QuerySet 一样。raw() 永远触发一个新的查询,而与之前的filter 无关。因此,它通常应该从 Manager 或一个全新的 QuerySet 实例调用。

不会返回QuerySets的方法

以下 QuerySet 方法评估 QuerySet 并返回而不是 a QuerySet 。这些方法不使用高速缓存(请参阅Caching and QuerySets)。这些方法每次被调用的时候都会查询数据库。

get:返回按照查询参数匹配到的对象,参数的格式应该符合 Field lookups的要求.如果匹配到的对象个数不只一个的话, get() 将会触发 MultipleObjectsReturned 异常.如果根据给出的参数匹配不到对象的话, get() 将触发 DoesNotExist 异常.

create:一个在一步操作中同时创建对象并且保存的便捷方法.

get_or_create:返回一个由 (object, created) 组成的元组,元组中的 object 是一个查询到的或者是被创建的对象, created 是一个表示是否创建了新的对象的布尔值。

update_or_create:通过给出的 kwargs 去从数据库中获取匹配的对象。如果找到匹配的对象,它将会依据 defaults 字典给出的值更新字段。

bulk_create:此方法以有效的方式(通常只有1个查询,无论有多少对象)将提供的对象列表插入到数据库中。

count:返回在数据库中对应的 QuerySet .对象的个数。 count() 永远不会引发异常。count() 在后台执行 SELECT COUNT(*) count() ,而不是将所有的记录加载到Python对象中并在结果上调用 len()。

in_bulk:获取主键值的列表,并返回将每个主键值映射到具有给定ID的对象的实例的字典。

iterator:评估 QuerySet (通过执行查询),并返回一个迭代器

latest|earliest:使用作为日期字段提供的 field_name ,按日期返回表中的最新对象。如果模型的Meta指定 get_latest_by ,则可以将 field_name 参数留给 earliest() 或者 latest() 。默认情况下,Django将使用 get_latest_by 中指定的字段。

first|last:返回结果集的第一个对象, 当没有找到时返回 None .如果 QuerySet 没有设置排序,则将会自动按主键进行排序。

aggregate(聚合查询):返回一个字典,包含根据 QuerySet 计算得到的聚合值(平均数、和等等)。 aggregate() 的每个参数指定返回的字典中将要包含的值。因为聚合也是查询表达式,你可以组合多个聚合以及值来创建复杂的聚合。使用关键字参数指定的聚合将使用关键字参数的名称作为Annotation 的名称。匿名的参数的名称将基于聚合函数的名称和模型字段生成。复杂的聚合不可以使用匿名参数,它们必须指定一个关键字参数作为别名。

exists:如果 QuerySet 包含任何结果,则返回 True ,否则返回 False 。

update:对指定的字段执行SQL更新查询,并返回匹配的行数(如果某些行已具有新值,则可能不等于已更新的行数)。update() 方法立即应用,对更新的 QuerySet 的唯一限制是它只能更新模型主表中的列,而不是相关模型。使用 update() 还可以防止在加载对象和调用 save() 之间的短时间内数据库中某些内容可能发生更改的竞争条件。

delete:对 QuerySet 中的所有行执行SQL删除查询。立即应用 delete() 。delete() 方法执行批量删除,并且不会在模型上调用任何 delete() 方法。但它会为所有已删除的对象(包括级联删除)发出 pre_delete 和 post_delete 信号。

字段查找

字段查询是指如何指定SQL WHERE 子句的内容. 它们通过 查询集 的 filter() ,exclude() and get() 的关键字参数指定.

聚合函数

Django 的 django.db.models 模块提供以下聚合函数。在 QuerySet 为空时,聚合函数函数将返回 None 。Count 是一个例外,如果 QuerySet 为空,它将返回 0 。

所有聚合函数具有以下共同的参数:

  • 表达(expression):引用模型字段的一个字符串,或者一个查询表达式。在复杂的计算中,聚合函数可以引用多个字段。
  • output_field:用来表示返回值的模型字段,它是一个可选的参数。
  • **kwargs:这些关键字参数可以给聚合函数生成的SQL 提供额外的信息。

avg:返回给定expression 的平均值,其中expression 必须为数值。

Count:返回与expression 相关的对象的个数。有一个可选的参数:distinct。如果 distinct=True ,Count 将只计算唯一的实例。

Max:返回expression 的最大值。

Min:返回expression 的最小值。

StdDev:返回expression 的标准差。有一个可选的参数:sample。默认情况下, StdDev 返回群体的标准差。但是,如果 sample=True ,返回的值将是样本的标准差。

Sum:计算expression 的所有值的和。

Variance:返回expression 的方差。有一个可选的参数:sample。默认情况下, Variance 返回群体的方差。但是,如果 sample=True ,返回的值将是样本的方差。

查询相关的类

Q() 对象:Q() 对象和 F 对象类似,把一个SQL 表达式封装在Python 对象中,这个对象可以用于数据库相关的操作。通常, Q() 对象 使得定义查询条件然后重用成为可能。

Prefetch() 对象(再看):Prefetch() 对象可用于控制 prefetch_related() 的操作。

查找 API 参考

查找 API 由两个部分组成: RegisterLookupMixin 类,它用于注册查找;查询表达式API,它是一个方法集,类必须实现它们才可以注册成一个查找。

Django 有两个类遵循查询表达式API,且Django 所有内建的查找都继承自它们:

  • Lookup :用于查找一个字段(例如 field_name__exact 中的 exact )
  • Transform :用于转换一个字段

查找表达式由三部分组成:字段部分,转换部分,查找部分

Django 使用 RegisterLookupMixin 来为类提供接口,注册它自己的查找。

无论你是自己定义还是让Django 为你提供一个主键字段, 每个模型都将具有一个属性叫做 pk 。

聚合补充

Django提供了两种生成聚合的方法:

  • 在查询集上生成聚合。从整个查询集生成统计值 aggregate
  • 为查询集的每一项生成聚合。为QuerySet中的每个对象都生成一个独立的汇总值 annotate。逐个对象的汇总结果可以由annotate()子句生成。当annotate()子句被指定之后,QuerySet中的每个对象都会被注上特定的值。

aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

与 aggregate() 不同的是, annotate() 不是一个终止子句。annotate()子句的返回结果是一个查询集 (QuerySet);这个 QuerySet可以用任何QuerySet方法进行修改,包括 filter(), order_by(), 甚至是再次应用annotate()。

在聚合函式中指定聚合字段时,Django 允许你使用同样的 双下划线 表示关联关系,然后 Django 在就会处理要读取的关联表,并得到关联对象的聚合。

数据库正反向查询要点

正向查询用字段,反向查询用表名小写加_set

多表查询

子查询:基于对象的跨表查询:

  • 查询结果有多个时需要加.all() ,如果是一个则直接拿到数据对象
  • 反向查询的结果有多个的时候加_set.all(),如果结果是一个则不需要加_set.all()

联表查询:基于双下划线的跨表查询

  • 聚合查询 aggregate一般配合分组查询使用
  • 分组查询 annotate
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值