Django-1.11中文文档-模型Models(一)
模型是数据信息的唯一并明确的来源。它包含了我们储存的数据的基本字段和行为。通常,每个模型映射到一张数据库表。
基本概念:
- 每个模型都是django.db.models.Model的一个子类
- 每个属性代表数据库中的一个字段
- 在这些基础上,Django为我们提供了一个自动生成的数据库访问API。
简单示例
下面的示例模型定义了一个Person,其拥有一个first_name和一个last_name属性。
from django.db import models class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
first_name和last_name是模型(model)的字段(fields).每个字段指定为类的一个属性,每个属性映射到数据库的一列(column)。
上面的Person模型将建立类似下面这样一个数据库:
CREATE TABLE myapp_person (
"id" serial NOT NULL primary_key,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
关于上面代码的一些技术注释:
- 上面数据表的名称"myapp_person",是从模型的元数据(metadata)自动导入的,但是可以覆写(overridden)。具体参见文档的Table names章节。
- 自动添加了一个id字段,该行为也可以被覆写。具体参见文档的Automatic primary_key fields章节
- 这是一段运用PostgreSQL语法建立数据表的SQL语句,但我们不用为此操心,针对后台settings file中设定好的数据库,Django都有量身定做的SQL。
运用模型
一旦定义好模型之后,需要告诉Django我们将使用这些模型。方法是通过编辑setting.py文件,在INSTALLED_APPS设定中添加包含了我们models.py的模块的名称。
例如,如果我们应用程序的模型存放在myapp.models模块中(该包结构在通过manage.py startapp命令创建应用程序时形成的),INSTALLED_APP应该一部分看起来如下:
INSTALLED_APPS = [
#...
'myapp',
#...
]
当添加apps到INSTALLED_APPS以后,确保要运行mangae.py migrate指令,有时候还需要先用manage.py makemigrations进行迁移。
字段(Field)
一个模型最重要也是唯一要求的部分,就是定义数据库的字段。字段是由类的属性指定的。注意不要选择与模型API冲突的字段名,如clean,save或者delete等。
示例:
from django.db import models class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100) class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
字段类型(Field types)
Each field in your model should be an instance of the appropriate Field
class. Django uses the field class types to determine a few things:
模型的每一个字段都是相应字段类的一个实例。Django用字段类的类型来决定一些东西:
- 列类型(column type),告诉数据库储存什么样的数据(比如INTERGER, VARCHAR, TEXT 等)。
- 渲染表单字段时用默认的HTML部件(比如<input type="text">, <select>等)
- Django的管理系统(admin)和自动生成的表单中,运用最低的验证要求。
Django拥有许多内置的字段类型;完整的清单参见model field reference。如果内置的字段满足不了要求,我们也可以方便的编写自己的字段,具体参见Writing custom model fields。
字段选项(Field options)
每个字段都有一些特定的参数(参见 model field reference),例如,CharField(及其子类)要求一个最大长度参数来规定数据库VARCHAR字段的大小。
也有一些每种字段都通用的参数,都是可选的。在reference中有完整的解释,这里对最常用的一些做个快速的概览:
null
如果值为True,在数据库中Django将把空值储存为Null。默认值为False。
blank
如果值为True,字段允许为空。默认值为False。
注意它与null是不同的。null是纯粹数据库相关的,而blank是验证相关的。如果一个字段设置了blank=True, 表单验证将允许输入空值。如果设置了blank=False,该字段则是必需的。
choices
一个包含了二维元组的可迭代对象(比如,列表或者元组)作为字段的选项,默认的表单部件将从标准的文本换成选择框,选项限定为choice参数。
chiices列表看起来像这样:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
每个元组中的第一个元素是将储存在数据库中的值。第二个元素将通过默认的表单部件显示,或者放在ModelChoiceField中。给出一个模型实例,可以通过get_FOO_display()方法来访问choices field正在显示的值。
示例:
from django.db import models class Person(models.Model):
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.shirt_size
'L'
>>> p.get_shirt_size_display()
'Large'
- default
- 字段的默认值。可以是一个值或者一个可调用的对象。如果是后者,每次新对象创建时都会调用。
- help text
- 表单部件显示附加的帮助信息。如果字段不是用在表单上,该参数对文档还是很有用的。
- primary_key
- 如果值为True,该字段设为模型的主键。
- 如果没有指定任何字段为主键,Django会自动添加一个IntegerField做为主键。所以如果不想覆写默认的主键,可以不设定任何字段的primary_key=True。
- 主键字段是只读的,如果你改写了一个原有主键的值然后储存,旧对象的旁边将会建立一个新对象。示例如下:
from django.db import models class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>
unique
- 如果为True,该字段在表中必须是唯一的。
- 再说一次,这些只是常用字段选项的简短描述,完整的信息请查看
- common model field option reference。
自动主键字段(Automatic primary_key fields)
- 默认情况下,Django中每个模型都有以下字段:
id = models.AutoField(primary_key=True)
这是一个自动增长的主键。
如果你想指定一个自定义的主键,只要将某个字段的选项设置primary_key=True。如果Django发现你已经明确了字段的主键(Field.primary_key),它就不会再添加自动的id列。
每个模型要求必须有一个字段设定为primary_key=True(明确指定的或者自动添加的都可以)。
详细字段名称(Verbose field names)
除ForeignKey, ManyToManyField 和 OneToOneField以外,每种字段都有一个第一位置参数-详细名称。如果该详细名称没有给出,Django会自动把字段的属性名称(下划线替换成空格)作为详细名称。
下面这个例子,详细名称是"person's first name":
first_name = models.CharField("person's first name", max_length=30)
下面这个例子,详细名称是"first name":
first_name = models.CharField(max_length=30)
ForeignKey, ManyToManyField 和 OneToOneField 要求第一位置参数为模型类,所以使用verbose_name关键字属性:
poll = models.ForeignKey(
Poll,
on_delete=models.CASCADE,
verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
verbose_name="related place",
)
有个惯例是不要将verbose_name的首字母大写,Django会再需要的时候自动将其首字母大写。
关系(Relationships)
很明显,关系型数据库的能力来源于相互关联的表。Django提供了方法定义三种最常见的数据库关系:many-to-one, many-to-many and one-to-one。
一对多关系(Many-to-one relationships)
通过django.db.models.ForeignKey来定义一对多关系。我们可以像使用其他字段类型一样:将其作为类属性包含在我们的模型中。
外键(ForeignKey)要求一个位置参数:该模型关联到哪个类。
比如,一个厂家制造了很多汽车,但是每辆汽车只有一个厂家,可以如下定义:
from django.db import models class Manufacturer(models.Model):
# ...
pass class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
# ...
你也可以创建一个递归关系recursive relationships(一个对象有一个指向自身的外键)以及与尚未定义的模型的关系relationships to models not yet defined,具体参见he model field reference。
建议,但没规定,将关联模型的小写名称作为外键字段的名称(上一个示例中的manufacturer)。当然,你可以叫外键字段任何名字,比如{
class Car(models.Model):
company_that_makes_it = models.ForeignKey(
Manufacturer,
on_delete=models.CASCADE,
)
# ...
参考信息
外键字段接收多种其他参数,具体参见the model field reference。这些选项帮助定义关系怎么工作,都是可选的。
关于访问向后相关(backwards-related)对象的细节,参见Following relationships backward example。
关于示例代码,参见Many-to-one relationship model example。
多对多关系(Many-to-many relationships)
要定义一个多对多关系,用MangToManyField。
我们可以像使用其他字段类型一样:将其作为类属性包含在我们的模型中。
MangToManyField要求一个位置参数:该模型关联到哪个类。
比如,一个披萨有多种配料,一种配料也可以用在多个披萨上。可以这样描述:
from django.db import models class Topping(models.Model):
# ...
pass class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
多对多关系中的额外字段
当你只需要处理简单的多对多关系时,比如混合搭配披萨和配料,标准的多对多字段就够了。然而,有时候你需要两个模型之间关系的辅助数据。
例如,设想有一种程序用来追踪音乐家属于哪个乐队。人和乐队之间是一种多对多的关系,所以我们可以用一个多对多字段来描述该关系。然而,还有很多其他相关信息我们也想收集,比如某人加入某个乐队的日期。
针对这种情况,Django允许我们指定模型,用来管理该多对多关系。这样我们可以在中间模型中设置额外的字段。通过设置through参数来指出哪个模型作为媒介,将中间模型与多对多字段联合起来。我们的乐队示例,代码应该差不多像这样:
from django.db import models class Person(models.Model):
name = models.CharField(max_length=128) def __str__(self): # __unicode__ on Python 2
return self.name class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership') def __str__(self): # __unicode__ on Python 2
return self.name class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
当我们建立中间模型时,我们明确指定了到该多对多关系相关模型的外键。此明确声明定义了这两个模型时怎么关联的。
中间模型中有一些约束:
- 中间模型必须有且只有一个到源模型(我们示例中的Group)的外键, 或者明确指定
ManyToManyField.through_fields。如果有超过一个外键而且没有指定through_fields,会引发验证错误。到目标模型(我们示例中的Person)的外键也有同样的限制。
- 当一个模型通过中间模型到自身有多对多关系,指向同一个模型的两个外键是允许的,但是它们要按多对多关系的不同侧来处理。如果存在超过两个外键,也必须跟上面一样指定through_fields,否则会引发验证错误。
- 当使用中间模型定义模型到自身的多对多关系时,必须使用
symmetrical=False
(参照 the model field reference)。
现在我们已经设置好ManyToMany字段来使用我们的中间模型(示例中的Membership),已为建立一些多对多关系做好准备。可以通过创建中间模型的实例来实行:
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason="Wanted to form a band.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
不像普通的多对多字段,我们不可以用add(), create(), 或者 set() 去创建关系:
>>> # The following statements will not work
>>> beatles.members.add(john)
>>> beatles.members.create(name="George Harrison")
>>> beatles.members.set([john, paul, ringo, george])
为什么?我们不能只创建人和乐队之间的关系,我们还需要指定Membership模型要求的关系的所有信息。简单的add, create无法指定额外的信息。所以,运用中间模型的多对多关系是禁用它们的。创建这种类型关系的唯一方法是创建中间模型的实例。
出于类似的原因, remove()方法也被禁用了。因为有时候remove()方法无法提供足够的信息来确认该删除哪一个中间模型实例:
>>> Membership.objects.create(person=ringo, group=beatles,
... date_joined=date(1968, 9, 4),
... invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This will not work because it cannot tell which membership to remove
>>> beatles.members.remove(ringo)
然而,clear()方法可以删除一个实例的所有多对多关系:
>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>
一旦通过创建中间模型实例建立了多对多关系,我们就可以进行查询了。就像普通多对多关系一样,我们可以通过相关模型的属性进行查询:
# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>
也可以通过中间模型的属性进行查询:
# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
... group__name='The Beatles',
... membership__date_joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>
如果需要访问中间模型的信息,我们可以直接对中间模型进行查询:
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
另一种访问相同信息的方法是从Person对象查询many-to-many reverse relationship:
>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
一对一关系(One-to-one relationships)
用OneToOneField定义一对一关系。像任何其他字段类型一样使用:作为属性包含在模型中。
如果一个对象继承自其他对象,一对一关系最适合用于它的主键。
OneToOneField要求一个位置参数:哪个模型是相关的。
例如,我们要建立一个关于“处所”的数据库,可能要在数据库中建立很多标准的东西,如地址、电话号码等。这时,如果你还想在这些处所的基础上再建立一个餐厅的数据库,不必在餐厅模型中再重复指定这些字段,只需要在餐厅模型中建立一个指向处所模型的一对一字段。(因为一间餐厅也是一个处所。实际上,这种情况我们通常使用继承inheritance,它是毫无疑问的一对一关系。)
跟外键一样,你也可以创建递归关系以及与尚未定义的模型的关系。
参考信息
完整实例请参见One-to-one relationship model example 。
一对一字段也接收一个可选的 parent_link
参数。
一对一字段类以前会自动成为模型的主键,现在不是这样了(尽管可以手动设置primary_key参数,如果我们想的话)。因此,现在同一个模型中可以有多个一对一字段。
跨文件的模型
访问其他应用的模型是非常容易的。 在文件顶部我们定义模型的地方,导入相关的模型就可以了。然后,无论在哪里需要的话,都可以引用它。例如:
from django.db import models
from geography.models import ZipCode class Restaurant(models.Model):
# ...
zip_code = models.ForeignKey(ZipCode)
字段命名的限制
Django 对字段的命名只有两个限制:
字段的名称不能是Python 保留的关键字,因为这将导致一个Python 语法错误。例如:
class Example(models.Model):
pass = models.IntegerField() # 'pass' is a reserved word!由于Django 查询语法的工作方式,字段名称中连续的下划线不能超过一个。例如:
class Example(models.Model):
foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
这些限制有变通的方法,因为没有要求字段名称必须与数据库的列名匹配。参 见db_column选项。
SQL 的保留字例如join、where 和select,可以用作模型的字段名,因为Django 会对底层的SQL 查询语句中的数据库表名和列名进行转义。 它根据你的数据库引擎使用不同的引用语法。
Django-1.11中文文档-模型Models(一)的更多相关文章
- Django 1.10中文文档-模型参考
模型字段 本文档包含了Django提供的全部模型 Field 包括 字段选项 和 字段类型 的API参考. 参见 如果内建的字段不能满足你的需求, 你可以蚕食 django-localflavor ( ...
- Django中文文档-模型Models(二):Meta选项、模型属性、模型方法
元数据(Meta)选项 使用内部的class Meta 定义模型的元数据,例如: from django.db import models class Ox(models.Model): horn_l ...
- Django 1.10中文文档-第一个应用Part2-模型和管理站点
本教程继续Part1.我们将设置数据库,创建您的第一个模型,并快速介绍Django的自动生成的管理网站. 数据库设置 现在,编辑mysite/settings.py.它是一个用模块级别变量表示Djan ...
- Django 1.10中文文档-执行查询
Django 1.10中文文档: https://github.com/jhao104/django-chinese-doc 只要创建好 数据模型, Django 会自动为生成一套数据库抽象的API, ...
- Django 1.10中文文档-聚合
Django 数据库抽象API 描述了使用Django 查询来增删查改单个对象的方法. 然而,有时候你要获取的值需要根据一组对象聚合后才能得到. 这个主题指南描述了如何使用Django的查询来生成和返 ...
- Django 1.10中文文档-第一个应用Part7-自定义管理站点
开发第一个Django应用,Part7 本教程上接Part6.将继续完成这个投票应用,本节将着重讲解如果用Django自动生成后台管理网站. 自定义管理表单 通过admin.site.register ...
- Django 1.10中文文档-第一个应用Part5-测试
本教程上接教程Part4. 前面已经建立一个网页投票应用,现在将为它创建一些自动化测试. 自动化测试简介 什么是自动化测试 测试是检查你的代码是否正常运行的行为.测试也分为不同的级别.有些测试可能是用 ...
- Django 1.10中文文档-第一个应用Part4-表单和通用视图
本教程接Part3开始.继续网页投票应用程序,并将重点介绍简单的表单处理和精简代码. 一个简单表单 更新一下在上一个教程中编写的投票详细页面的模板polls/detail.html,让它包含一个HTM ...
- Django 1.10中文文档-第一个应用Part3-视图和模板
本教程上接Django 1.10中文文档-第一个应用Part2-模型和管理站点.我们将继续开发网页投票这个应用,主要讲如何创建一个对用户开放的界面. 概览 视图是Django应用中的一“类”网页,它通 ...
随机推荐
- 浅谈Webpack模块打包工具一
为什么要使用模块打包工具 1.模块化开发ES Modules存在兼容性问题 打包之后成产阶段编译为ES5 解决兼容性问题 2.模块文件过多 网络请求频繁 开发阶段把散的模块打包成一个模块 解决网络请 ...
- HDU 6762 Mow (2020 Multi-University Training Contest 1 1012) 半平面交
Mow 题目链接 分析 将多边形的边向内部缩 r 个单位长度,然后这些边所围成的内部区域,就是圆心的合法范围,该范围也是一个多边形,假设面积是\(a\),周长是\(b\),那么可以知道圆可以覆盖的面积 ...
- HDU 3449 依赖背包
这道题虽然水水的,但是还是成功地给我增加了10多个WA. 最开始拿着题,一看,依赖背包嘛~直接DFS树形DP嗨起来,甚至连内存都没有算一下,3MLE: 然后又仔细看了一下题,没有必要用树形背包来做嘛, ...
- Gym 101485 E Elementary Math 网络流 或者 二分图
题意: 输入一个n,后面输入n行,每一行两个数a.b.你可以对a.b进行三种操作:+.-.* 你需要保证对每一行a.b选取一个操作得到一个结果 你要保证这n行每一个式子选取的操作之后得到的结果都不一样 ...
- 【bzoj 3433】{Usaco2014 Jan} Recording the Moolympics(算法效率--贪心)
题意:给出n个区间[a,b),有2个记录器,每个记录器中存放的区间不能重叠.求2个记录器中最多可放多少个区间. 解法:贪心.只有1个记录器的做法详见--关于贪心算法的经典问题(算法效率 or 动态规划 ...
- 使VS开发的程序在Win7系统运行时自动提升权限
软件开发时,总是会遇到在Win7系统上运行不起来或者异常的情况,这通常是用户的权限不够引起的. 下面提供一个可以使程序运行时,自动提升用户权限的方法. 1.右键点击启动项目,单击"属性&qu ...
- 前端接收后端文件流导出excel文档遇到的问题
先上代码: Vue.prototype.download = function(oUrl, filename) { this.axios .get(oUrl, { responseType: 'arr ...
- RESTful 架构 && RESTful API
RESTful 架构 && RESTful API REpresentational State Transfer (REST) 具象状态传输https://en.wikipedia. ...
- Angular 2 for 2017 web full stack development
1 1 1 Angular 2 for 2017 web full stack development 1 1 https://angular2.xgqfrms.xyz/ https://ng2-he ...
- JavaScript interview Question - Create a Array with two papameters without using loop!
JavaScript interview Question - Create a Array with two papameters without using loop! JavaScript - ...