模型是数据唯一而且准确的信息来源。它包含正在储存的数据的重要字段和行为。一般来说,每一个模型都映射一个数据库表。
- 每个模型都是一个 Python 的类,这些类继承 django.db.models.Model
- 模型类的每个属性都相当于一个数据库的字段。
- 访问数据库的 API
1. 模型样例
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 是模型的字段。每个字段都被指定为一个类属性,并且每个属性映射为一个数据库字段。
上面的 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 是自动从某些模型元数据中派生出来,但可以被改写。
- id 字段会被默认自动添加为主键,但是这种行为可以被改写。
2. 使用模型
修改设置文件中的 INSTALLED_APPS,在这个设置中添加包含 models.py 文件的应用的名字(应用是由 python manage.py startapp 命令创建)。
INSTALLED_APPS = [ 'myapp', ]
在 INSTALLED_APPS 添加新的应用后,依次执行命令:python manage.py makemigrations,python manage.py migrate 来创建数据库表。
3. 字段定义
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): musician = models.ForeignKey(Musician, on_delete=models.CASCADE) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
4. 字段类型
模型中每一个字段都应该是相应类的实例, Django 利用这些字段类来实现下面这些功能。
- 字段类型用以指定数据库数据类型
- 默认的 HTML 表单输入框
- 用于 Django admin 和自动生成表单的基本验证
5. 字段选项
每一种字段都需要指定一些特定的参数。例如 django.db.models.CharField 需要接收一个 max_length 参数,用以指定数据库存储数据时用的 VARCHAR 大小。
一些可选的参数是通用的,可以用于任何字段类型,下面介绍一部分经常用到的通用参数:
(1)null 如果设置为 True,当该字段为空时,Django会将数据库中该字段设置为 NULL 。默认为 False 。
(2)blank 如果设置为 True,该字段允许为空。默认为 False 。blank 涉及表单验证,如果一个字段设置为 blank=True,表单接收的数据该字段值允许为空,blank=False 时,不允许为空。
(3)choices 该参数接收一个可迭代的列表或元组(基本单位为二元组)。如果指定了该参数,在实例化模型时,该字段只能取选项列表中的值。每个二元组的第一个值会储存在数据库中,而第二个值将只会用于显示。对于一个模型实例,要获取该字段二元组中的第二个值,使用 get_FOO_display() 方法。
(4)default 该字段的默认值。可以是一个值或者可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。
(5)help_text 对字段的帮助说明,会显示在表单中。
(6)primary_key 如果设置为 True,将该字段设置为该模型的主键。在一个模型中,如果你没有对任何一个字段设置 primary_key=True 选项,Django 会自动添加一个 IntegerField 字段,用于设置为主键。
(7)unique 如果设置为 True,这个字段必须在整个表中保持值唯一。
4. 自动设置主键
默认情况下, Django 会给每一个模型添加下面的字段:
id = models.AutoField(primary_key=True)
这是一个自增的主键。如果你想指定设置为为主键的字段, 在你想要设置为主键的字段上设置 primary_key=True 选项。如果 Django 看到你显式的设置了 Field.primary_key,将不会自动在表(模型)中添加 id 列。
每个模型都需要拥有一个设置了 primary_key=True 的字段。
5. 备注名
除了 ForeignKey, ManyToManyField 和 OneToOneField,任何字段类型都接收一个可选的参数 verbose_name,如果未指定该参数值,Django 会自动使用该字段的属性名作为该参数值,并且把下划线转换为空格。
first_name = models.CharField("person's first name", max_length=30) # 备注名为 "person's first name" first_name = models.CharField(max_length=30) # 备注名为 "first name"
ForeignKey,ManyToManyField 和 OneToOneField 接收的第一个参数为模型的类名,后面可以添加一个 verbose_name 参数:
poll = models.ForeignKey(Poll, on_delete=models.CASCADE, verbose_name="the related poll")
一般情况下不需要将 verbose_name 值首字母大写,必要时 Djanog 会自动把首字母转换为大写。
6. 关联关系
关系型数据库的强大之处在于各表之间的关联关系。Django 提供了定义三种最常见的数据库关联关系的方法:多对一,多对多,一对一。
6.1 Many-to-one relationships
定义一个多对一的关联关系,使用 django.db.models.ForeignKey 类。就和其他 Field 字段类型一样,只需要在你模型中添加一个值为该类的属性。
例如,如果一个 Car 模型有一个制造者 Manufacturer,就是说一个 Manufacturer 制造许多辆车,但是每辆车都属于某个特定的制造者,那么使用下面的方法定义这个关系:
from django.db import models class Manufacturer(models.Model): pass class Car(models.Model): manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
建议设置 ForeignKey 字段名为想要关联的模型名,当然你也可以随意设置为你想要的名称。
6.2 Many-to-many relationships
定义一个多对多的关联关系,使用 django.db.models.ManyToManyField 类。就和其他 Field 字段类型一样,只需要在你模型中添加一个值为该类的属性。
例如:如果 Pizza 含有多种 Topping(配料),也就是一种 Topping 可能存在于多个 Pizza 中,并且每个 Pizza 含有多种 Topping,那么可以这样表示这种关系:
from django.db import models class Topping(models.Model): pass class Pizza(models.Model): toppings = models.ManyToManyField(Topping)
建议设置 ManyToManyField 字段名为一个复数名词,表示所要关联的模型对象的集合。
对于多对多关联关系的两个模型,可以在任何一个模型中添加 ManyToManyField 字段,但不能同时在两模型中添加该字段,只能选择一个模型设置该字段。
一般来讲,应该把 ManyToManyField 实例放到需要在表单中被编辑的对象中。toppings 被放在 Pizza 中,而不是 Topping 中指向 pizzas 的 ManyToManyField 实例。因为相较于配料被放在不同的披萨当中,披萨当中有很多种配料更加符合常理。按照先前说的,在编辑 Pizza 的表单时用户可以选择多种配料。
6.3 在多对多关系中添加额外的属性字段
如果你只是想要一个类似于记录披萨和配料之间混合和搭配的简单多对多关系,标准的 ManyToManyField 就足够你用了。然而,有的时候你可能会需要在两个模型的关系中记录更多的数据。
举例来讲,考虑一个需要跟踪音乐人属于哪个音乐组的应用程序。在人和他们所在的组之间有一个多对多关系,你可以使用 ManyToManyField 来代表这个关系。然而,你想要记录更多的信息在这样的所属关系当中,比如你想要记录某人是何时加入一个组的。
对于这些情况,Django允许你指定用于控制多对多关系的模型。你可以在中间模型当中添加额外的字段。在实例化 ManyToManyField 的时候使用 through 参数指定多对多关系使用哪个中间模型。对于我们举的音乐家的例子,代码如下:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __str__(self): 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()
在设置中间模型的时候,你需要显式地为多对多关系中涉及的模型指定外键。这种显式声明定义了这两个模型之间的关系。
在中间模型当中有一些限制条件:
- 中间模型要么有且仅有一个指向源模型(例中的 Group)的外键,要么必须通过 ManyToManyField.through_fields 参数在多个外键当中手动选择一个外键,如果有多个外健且没有用 through_fields 参数选择一个的话,会出现验证错误。对于指向目标模型(例中的 Person)的外键也有同样的限制。
- 在一个用于描述模型当中自己指向自己的多对多关系的中间模型当中,可以有两个指向同一个模型的外健,但这两个外健分别代表多对多关系的两端。如果外健的个数超过两个,必须指定 through_fields 参数,否则会出现验证错误。
- 在定义模型自己指向自己的多对多关系时,如果使用中间模型,必须定义 symmetrical=False 。
6.4 One-to-one relationships
使用 OneToOneField 来定义一对一关系。就像使用其他类型的 Field 一样,在模型属性中包含它。
当一个对象以某种方式扩展另一个对象时,这对该对象的主键非常有用。
OneToOneField 字段还接受一个可选的 parent_link 参数。