Django(3):数据模型定义
目录
- 模型类
- 字段限定规则
- 属性字段类型
- 元数据选项
- 总结
上一章:通过博客项目熟悉django项目开发基本流程
数据模型是业务处理的核心。Django本身封装了大量与数据模型对象处理相关的功能,但是只有按照Django提供的数据模型定义方式,才能使用这些功能。
我们前面知道,一个数据模型会对应数据库中一张表,而一张表会有表属性、字段属性等,为了和数据库对应,Django中对数据模型也封装了很多属性。
下面以上一章用户模块的Author为例,一一介绍,内容很多很全,建议收藏食用。
模型类
在Django框架中对于数据模型的定义和封装,有如下一些要求:
- 必须继承
django.db.models.Model
- 必须使用Django内置函数创建属性
- 对对象数据的增删改查操作,可以直接使用Django封装的函数
以上一章博客为例,下面是对Author模型进一步完善。
class Author(models.Model):
"""用户类型:博客作者"""
GENDER = (
('0', '女'),
('1', '男'),
)
AUTHOR_STATUS = {
('0', '正常'),
('1', '锁定',),
('2', '删除'),
}
# 作者编号
# id = models.AutoField(primary_key=True, verbose_name='作者编号')
id = models.UUIDField(primary_key=True, verbose_name='作者编号')
# 登录账号
username = models.CharField(max_length=50, verbose_name='登录账号')
# 登录密码
password = models.CharField(max_length=50, verbose_name='登录密码')
# 真实姓名
realname = models.CharField(max_length=20, verbose_name='作者姓名')
# 年龄
age = models.IntegerField(default=0, verbose_name='作者年龄')
# 性别
gender = models.CharField(max_length=1, choices=GENDER, verbose_name='性别')
# 邮箱
email = models.EmailField(verbose_name='联系邮箱')
# 手机
phone = models.CharField(max_length=20, verbose_name='联系电话')
# 用户状态
status = models.CharField(max_length=5, choices=AUTHOR_STATUS, verbose_name='用户状态')
# 个人介绍
intro = models.TextField(verbose_name='个人介绍')
# 备注信息
remark = models.TextField(verbose_name='备注信息')
class Meta:
# 后台管理系统中的名称
verbose_name_plural = '作者'
def __str__(self):
return self.realname
在上面的代码中,使用了大量Django封装的方法和字段你限定规则,在后面的属性字段类型部分会详细讲解每一种字段类型和限定规则的使用方式,只有通过这种方式添加的限定处理规则,才能让Django封装的工具类型的功能作用在当前数据类型的属性和锁创建的对象上。
如下图:
字段限定规则
在定义模型里属性字段时,有很多字段限定规则。
Django默认提供了17种字段限定规则。如下:
1.null
赋值True/False。属性对应的数据表中的字段是否允许为空。
注意:如果为True,不要为改字段添加唯一性约束,否则造成数据唯一性冲突。
代码如下:
name = models.IntegerField(default=0, null=True)
2.blank
赋值True/False。blank只针对表单数据校验,如果表单某个输入框允许输入空值,那么这个空值并不是null值,而是空字符串,这样无法通过表单验证,如果blank=True,则是允许表单里填写空字符串这样的空白。代码如下:
nickname = models.CharField(max_length=20, null=True, blank=True)
3.choices
赋值一个可以迭代的元组或列表。适合一些枚举字段,如性别、省份等。代码如下:
GENDER = (
('0', '女'),
('1', '男'),
)
gender = models.CharField(max_length=1, choices=GENDER, verbose_name='性别')
4.db_column
指定当前属性在数据库中表字段名字。默认就是属性名,一般不建议修改。代码如下:
email = models.EmailField(verbose_name='联系邮箱', db_column='user_email')
5.db_index
赋值True/False。指定属性队形的数据表字段是否支持索引。对于改查较多、增删较少的表,通常会在查询条件字段添加索引支持。代码如下:
username = models.CharField(max_length=50, verbose_name='登录账号', db_index=True)
6.db_tablespace
如果已经为模型类中的某个属性添加了索引支持,可通过db_tablespace指定索引操作使用的表空间。默认是项目的DFAULT_INDEX_TABLESPACE表空间。在项目中改规则用的不多。
7.default
指定属性默认值或者一个可以调用的函数,暂不支持Lambda表达式。代码如下:
def contact_default():
return {"email":"abc@example.com"}
contact_info = models.JSONField("ContactInfo", deault=contact_default)
age = models.IntegerField(default=0, verbose_name='作者年龄')
8.editable
赋值True/False。指定属性是否可编辑,默认为True,可以在表单和管理员界面对该属性字段进行编辑。使用较少。代码如下:
status = models.CharField(max_length=5, choices=AUTHOR_STATUS, verbose_name='用户状态', editable=False)
9.error_message
赋值一个字典,字典中的key是一个限定规则的名称,Value是对应的限定规则。如果验证失败,则需要展示消息内容,主要在封装表单时使用。代码如下:
email = models.EmailField(error_message={'required':u'邮箱不能为空'})
10.help_text
赋值字符串数据,用于显示帮助信息。指定该属性,会在表单操作时显示自定义的属性字段的提示信息,主要辅助用户输入数据。如下:
status = models.CharField(max_length=5, choices=AUTHOR_STATUS, verbose_name='用户状态', help_text='必须选择其中一个状态')
11.primary_key
赋值True/False。设置主键约束。如果定义模型时没用指定主键,Django默认为模型自定添加一个AutoField字段并设为主键。代码如下:
id = models.AutoField(primary_key=True, verbose_name='作者编号')
另外,如果要设置联合主键,可以通过元数据设置。代码如下:
class_meta:
# 为多个属性添加唯一性约束
unique_together = ('id', 'username')
12.unique
赋值True/False。设置属性的唯一索引。代码如下:
nickname = models.CharField(max_length=20, verbose_name='作者昵称', unique=True)
13.unique_for_date
赋值True/False。设置日期属性DataField/DataTimeField不会出现重复数据。
14.unique_for_month
赋值True/False。设置某个日期属性的月份不会出现重复数据。
15.unique_for_year
赋值True/False。设置某个日期属性的年份不会出现重复数据。
16.verbose_name
赋值字符串,设置属性在后台管理系统中展示的数据。
17.validators
一般情况下,用于对当前模型类的属性进行验证。代码如下:
# 验证数据是否为偶数
def validate_even(value):
if value % 2 != 0:
raise ValidationError(
_('%(value)s is not an even number'),
params={'value':value}
)
class MyModel(models.Model):
even_field = models.IntegerField(validators=[validate_even])
属性字段类型
字段类型觉得数据存放的格式。
Django中定义了26种表示不同数据的字段类型。
1.AutoField
自动增长类型。存储自动增长的整数属性字段,中小型项目长用于定义表中字段。注意通常在定义模型时不需要指定主键字段,主键会被自动添加到模型类对应的数据表中。
以下两种方式是一样的:
class Author(models.Model):
"""用户类型:博客作者"""
# 作者编号
id = models.AutoField(primary_key=True)
# 登录账号
username = models.CharField(max_length=50, verbose_name='登录账号', db_index=True)
class Author(models.Model):
"""用户类型:博客作者"""
# 登录账号
username = models.CharField(max_length=50, verbose_name='登录账号', db_index=True)
2.BigAutoField
自动增长类型。上面普通的自增长类型范围太小,无法满足大量数据操作,BigAutoField字段类型存储范围为1~9 223 372 036 854 775 807。代码如下:
id = models.BigAutoField(primary_key=True,)
3.IntegerField
整数类型。代码如下:
age = models.IntegerField(default=0, verbose_name='作者年龄')
4.SmallIntegerField
小整数型。底层通过继承IntegerField实现,取值范围为-32768 ~ 32767。代码如下:
# 员工打卡计数
card_login = models.SmallIntegerField(default=0)
5.BigIntegerField
大整数数据类型。存储范围为-9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807。代码如下:
history_operations = models.BigIntegerField(default=0, verbose_name='历史操作记录计数')
6.PositiveIntegerField
正整数类型。底层通过继承IntegerField实现,取值范围为0 ~ 2147483647。代码如下:
models.PositiveIntegerField(default=0)
7.PositiveSmallIntegerField
正整数类型,与PositiveIntegerField类似,取值范围小,为0 ~ 32767。代码如下:
models.PositiveSmallIntegerField(default=0)
8.FloatField
浮点数类型。底层通过float封装实现。代码如下:
# 用户等级
user_level = models.FloatField(default=0)
9.DecimalField
固定精度的数字类型。两个主要的限定参数:max_digits,指定允许的最大位数;decimal_places,指定保留的小数位数。代码如下:
models.DecimalField(max_digits=19, decimal_places=10)
10.CharField
字符类型。对应如mysql中的varchar
类型,须指定max_length
。代码如下:
username = models.CharField(max_length=50)
11.BooleanField
布尔类型。只能是True/False。代码如下:
is_manager = models.BooleanField(default=False)
12.NullBooleanField
布尔类型。用于描述一个可以存储None、False或True数据的属性。在Django2.0以上版本建议使用BooleanField代替。
13.DateField
日期类型。用于创建只包含年月日数据属性字段。如果要设置默认值,可以使用下面几种方式:
# 账号创建时间,可以用datetime.date.today设置默认之间
create_date = models.DateField(default=datetime.date.today)
# 可以使用django.utils.timezone.now设置默认之间
create_date = models.DateField(default=django.utils.timezone.now)
但是官方建议使用auto_now_add
和auto_now
。auto_now_add是指在第一次创建时把属性对应字段设置为当前系统时间,并在之后的任何操作中都不在修改(默认editable=False);auto_now是在创建之后,每次保存和更新时,也会把属性对应字段设置为当前系统时间。
一般传创建时间使用auto_now_add,更新时间使用auto_now。如下:
# 创建时间
create_date = models.DateField(auto_now_add=True)
# 最后修改时间
update_date = models.DateField(auto_now=True)
14.DateTimeField
日期时间类型。包含日期和时间。可以设置auto_now_add、auto_now、default等属性。代码如下:
# 账号创建时间,可以用datetime.date.now设置默认之间
create_time = models.DateTimeField(default=datetime.date.now)
# 可以使用django.utils.timezone.now设置默认之间
create_time = models.DateTimeField(default=django.utils.timezone.now)
和DateField一样,官方建议使用auto_now_add
和auto_now
。
15.TimeField
时间类型。描述时分秒数据属性。和DateField一样,官方建议使用auto_now_add
和auto_now
设置默认值。代码如下:
# 可以使用django.utils.timezone.now设置默认之间
update_time = models.TimeField(default=django.utils.timezone.now)
# 建议使用`auto_now_add`和`auto_now`设默认值
update_time = models.TimeField(auto_now=True)
16.TextField
长字符串类型。通常用于存储大文本数据。代码如下:
content = models.TextField()
17.BinaryField
二进制数据类型。存储单位可以是bytes、bytearray、memoryview。在默认情况下字段类型的editable为False,二进制不会直接显示在任何表单数据中的。但是一般不会直接把二进制数据存在数据库。代码如下:
header_img = models.BinaryField(max_length=20000)
18.EmailField
邮箱类型。底层通过CharField实现,同时进行邮箱格式验证。代码如下:
email = models.EmailField(verbose_name='联系邮箱')
19.ImageField
图像类型。继承自FilePathField,增加了图像验证功能。代码如下:
# 用户头像
header_img = models.ImageField(upload_to='upload/files/headers/')
20.FileField
文件类型。在文件双穿时用于接受表单数据。在示例项目中,通常文件被存在指定文件夹或云服务器上,字段里只存储文件路径字符串,使用upload_to
参数限定文件夹路径。同时可以通过max_length
限定上传文件的大小。代码如下:
content_attachment = models.FileField(upload_to='upload/files/')
# 在路径中可以直接包含时间符号,如%Y会被自动替换成当前年份
content_attachment = models.FileField(upload_to='upload/files/%Y/%m/%d/')
21.FilePathField
文件检索类型。用于在指定路径中查询匹配的文件数据,用的比较少。
三个主要参数:path,指定要检索的文件路径,必选;match,指定搜索规则正则表达式;recursive,是否查询path的子目录。代码如下:
models.FilePathField(path='/home/images', match='foo.*', recursive=True)
22.GenericIPAddressField
IP地址类型。可以存储IPv4或IPv6类型的IP地址。有两个限定规则的参数:protocol,指定数据格式,可以为IPv4、IPv6或both(默认)。参数数据不区分大小写;unpack_ipv4,指定在protocol为both的情况下,将IPv6地址自动转为IPv4。代码如下:
remote_ip = models.GenericIPAddressField()
23.URLField
URL类型。底层通过继承CharField实现,并添加了URL验证机制的字符串字段。代码如下:
personal_page = models.URLField()
24.SlugField
短标签类型。底层通过CharField实现。其中只能包含字母、数字、下划线或者连字符。通常用作URL地址。代码如下:
personal_page = models.SlugField()
25.UUIDField
唯一标识类型。在实际开发中,之间会使用唯一标识字符串处理。代码如下:
# 作者编号
# id = models.AutoField(primary_key=True, verbose_name='作者编号')
id = models.UUIDField(primary_key=True, verbose_name='作者编号')
26.DurationField
时间段类型,封装两个时间之间的差值计算,这样的算术运算在PostgreSQL数据库中得到非常友好的支持,在其他数据库不太理想,因此不建议使用。
通过上面的介绍后,下面对博客项目中的作者Author模型进行完善,代码如下:
class Author(models.Model):
"""用户类型:博客作者"""
GENDER = (
('0', '女'),
('1', '男'),
)
AUTHOR_STATUS = {
('0', '正常'),
('1', '锁定',),
('2', '删除'),
}
# 作者编号
# id = models.AutoField(primary_key=True, verbose_name='作者编号')
id = models.UUIDField(primary_key=True, verbose_name='作者编号', auto_created=True, default=uuid4)
# 登录账号
username = models.CharField(max_length=50, verbose_name='登录账号', unique=True, db_index=True)
# 登录密码
password = models.CharField(max_length=50, verbose_name='登录密码')
# 真实姓名
realname = models.CharField(max_length=20, verbose_name='作者姓名', default='待完善', null=True, blank=True, db_index=True)
# 用户昵称
nickname = models.CharField(max_length=20, verbose_name='作者昵称', unique=True, null=True, blank=True, db_index=True)
# 年龄
age = models.IntegerField(default=0, verbose_name='作者年龄')
# 性别
gender = models.CharField(max_length=1, choices=GENDER, verbose_name='性别', null=True, blank=True)
# 邮箱
email = models.EmailField(verbose_name='联系邮箱', null=True, blank=True, db_index=True)
# 手机
phone = models.CharField(max_length=20, verbose_name='联系电话', db_index=True, null=True, blank=True)
# 用户状态
status = models.CharField(max_length=5, choices=AUTHOR_STATUS, verbose_name='用户状态', help_text='必须选择其中一个状态',
default=0)
# 账号注册时间
create_time = models.DateTimeField(auto_now_add=True, verbose_name='注册时间')
# 最后修改时间
update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间')
# 个人主页
personal_page = models.URLField(verbose_name='个人主页', null=True, blank=True)
# 个人介绍
intro = models.TextField(verbose_name='个人介绍', null=True, blank=True)
# 备注信息
remark = models.TextField(verbose_name='备注信息', null=True, blank=True)
class Meta:
# 后台管理系统中的名称
verbose_name_plural = '作者'
def __str__(self):
return "账号:{};昵称:{};姓名:{}".format(self.username, self.nickname, self.realname)
元数据选项
通过Meta类封装的属性称为元数据,它是区别属性的数据,用于管理数据模型。
1.abstract
元数据抽象。设置为abstract = True,可以让当前所属类型为抽象类型。在Django中抽象类型最大的特点是不会同步生成数据表,在项目中主要做继承使用,提高代码的复用性和功能的可扩展性。代码如下:
class BaseModel:
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间')
class Meta:
abstract = True
2.db_table
自定义在数据库创建的当前类型对应的数据表名称。默认数据表名称是"当前类型的模块名_类型名称"。
3.db_tablespace
自定义当前类型对应的数据库表存储的表空间,默认通过DEFAULT_TABLESPACE设置指定。
4.unique_together
指定联合主键,使用较多。代码如下:
unique_together = ('realname', 'nickname')
5.indexes
为当前模型类添加索引的属性列表,代码如下:
indexes = [
models.Index(fields=['username', 'realname', 'nickname'])
]
6.verbose_name
指定模型的展示名称,用于在后台管理系统界面展示。
7.ordering
指定当前模型的排序字段,主要是一个当前类型的属性名称组成的元组或列表,默认按照指定字段升序,可以再属性前加"-"符号变为降序。代码如下:
# 按照创建时间降序排序
ordering = ['-create_time']
# 按照账号升序排序
ordering = ['username']
# 先按照创建时间降序排序,再按照账号升序排序
ordering = ['-create_time', 'username']
8.default_related_name
自定义关联模型类对象的查询名称。如果一个模型被其他模型引用,使得多个模型之间有关联关系,可以通过该模型的全部小写的语法访问关联的对象数据。default_related_name一般用来简写名称。代码如下:
class Author(models.Model):
pass
class Article(models.Model):
author = models.Foreignkey(Author, on_delete=models.CASCADE)
...
class Meta:
# 设置关联模型类对象的查询名称
default_related_name = 'art'
这样可以通过下列查询,结果:
>>> author = AUthor.objects.get(pk=1)
>>> article = Article.objects.get(author=author)
ERROR(错误)以前的的操作方式不能直接使用了
>>> article = Article.objects.get(art=author)
具体的数据关联操作,后面还会讲解。
9.get_last_by
自定义数据的排序规则,配置Django的latest()/earliest()方法使用。代码如下:
get_last_by = 'create_time'
10.order_with_respect_to
指定关联模型的排序字段,只要用在关联模型上,Django会自动提供获取排序后的关联数据de API,有get_<related>_order()
和set_<related>_order()
,用于获取和设置关联的数据对象。代码如下:
class Author(models.Model):
pass
class Article(models.Model):
author = models.Foreignkey(Author, on_delete=models.CASCADE)
...
class Meta:
# 设置关联模型类对象的查询名称
order_with_respect_to = 'author'
这样可以通过下列查询,结果:
>>> author = AUthor.objects.get(pk=1)
>>> article = Article.objects.get_article_order()
在得到关联对象后,还会自动获取两个API,get_previous_in_order()
和get_next_in_order()
,分别用于获取前一条数据和后一条数据。代码如下:
>>> author = AUthor.objects.get(pk=3)
>>> article.get_previous_in_order()
>>> article.get_next_in_order()
11.app_label
模型所属的App的声明标记。如果创建的模块App没有在根目录管理项目的INSTALLED_APPS注册,则必须通过app_label声明它属于哪个App。
12.managed
模型类管理功能开关,默认为True,表示Django会自动根据当前模型类来管理数据类型一级数据表的周期。如果设置False,Django不会自动创建数据表等。
13.base_manager_name
模型管理器名称。模型管理器是Django提供给模型类的API操作接口。
14.default_manager_name
自定义模型管理器名称。
15.permissions
权限分配。可以赋值一个由权限码和权限描述组成的元组或列表,用于指定魔心类的对象在创建时就添加自定义的操作权限。代码如下:
permissions = (('comment_publish', '发表评论权限'),)
16.default_permissions
设置当前类型的默认权限。在不指定该选项的情况下,Django默认提供了add、change和delete三个权限。
17.proxy
指定代理模式的模型继承方式
18.required_db_features
声明模型依赖的数据库功能。
19.required_db_vendor
声明模型支持的数据库。Django默认支持SQLite、PostgreSQL、MySQL、Oracle数据库。
20.select_on_save
指定是否使用Django1.6版本之前的django.db.models.Model.save()
函数存储数据。对于老版本的一些方法的兼容处理方式,现在不再推荐使用。
21.verbose_name_plural
指定模型的展示名称,主要针对英文名称的复数形式。如果需要中文名称展示,指定verbose_name即可。
22.label
只读元数据,用于获取当前模块名称。label等同于author.Author。
23.label_lower
功能同label,获取小写的,label_lower等同于author.author。
总结
通过以上三个纬度学习,就可以完全定义出自己模型类,来满足各种需求了。下一章介绍数据库处理相关的操作。
码字不易,求个三连!!!