Django-模型
概述
- Django对各种数据库都提供了良好的支持
- Django为这些数据库提供了统一的调用接口API,我们可以根据业务需求选择使用不同的数据库
配置MySQL
-
将
DATABASES
做如下修改1
2
3
4
5
6
7
8
9
10DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '数据库名',
'USER': '用户名',
'PASSWORD': '密码',
'HOST': '主机',
'PORT': '端口'
}
}
ORM
-
概述
- 对象-关系-映射
- 将对象的操作自动转换成对应数据库语句
-
任务
- 根据类生成表结构
- 将对象、列表的操作转换为SQL语句
- 将SQL查询到的结果转换为对象、列表
-
优点
- 极大的减少开发人员的工作量,不需要面对因数据库变更而导致代码无效
-
图解
定义模型
-
模型、属性、表、字段间的关系
- 一个模型在数据库中对应一张表,在模型中定义的属性,对应该模型对照表中的一个字段
-
定义属性
-
概述
- django根据属性的类型确定以下信息
- 当前选择的数据库支持字段的类型
- 渲染管理表单时使用的默认html控件
- 在管理站点最低限度的验证
- django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
- 属性命名限制
- 不能是python的保留关键字
- 由于django的查询方式,不允许使用连续的下划线
- django根据属性的类型确定以下信息
-
库
- 定义属性时,需要字段类型,字段类型被定义在
django.db.models.fields
目录下,为了方便使用,被导入到django.db.models
中 - 使用方式
- 导入
from django.db import models
- 通过
models.Field
创建字段类型的对象,赋值给属性
- 导入
- 定义属性时,需要字段类型,字段类型被定义在
-
逻辑删除
- 对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
-
字段类型
-
AutoField
一个
IntegerField
,根据可用的 ID 自动递增。你通常不需要直接使用它;如果你没有指定,主键字段会自动添加到你的模型中。参见 自动设置主键。 -
BigAutoField
一个 64 位整数,与
AutoField
很相似,但保证适合1
到9223372036854775807
的数字。 -
BigIntegerField
一个 64 位的整数,和
IntegerField
很像,只是它保证适合从-9223372036854775808
到9223372036854775807
的数字。该字段的默认表单部件是一个NumberInput
。 -
BinaryField
一个用于存储原始二进制数据的字段。可以指定为
bytes
、bytearray
或memoryview
。 -
BooleanField
一个 true/false 字段。该字段的默认表单部件是
CheckboxInput
,或者如果null=True
则是NullBooleanSelect
。当Field.default
没有定义时,BooleanField
的默认值是None
。 -
CharField
一个字符串字段,适用于小到大的字符串。对于大量的文本,使用
TextField
。该字段的默认表单部件是一个TextInput
。 -
DateField
- 一个日期,在 Python 中用一个
datetime.date
实例表示。有一些额外的、可选的参数。 - DateField.auto_now
- 每次保存对象时,自动将该字段设置为当前时间。对于“最后修改”的时间戳很有用。请注意,当前日期 总是 被使用,而不仅仅是一个你可以覆盖的默认值。
- 只有在调用
Model.save()
时,该字段才会自动更新。当以其他方式对其他字段进行更新时,如QuerySet.update()
,该字段不会被更新,尽管你可以在这样的更新中为该字段指定一个自定义值。
- DateField.auto_now_add
- 当第一次创建对象时,自动将该字段设置为当前时间。对创建时间戳很有用。请注意,当前日期是 始终 使用的;它不是一个你可以覆盖的默认值。因此,即使你在创建对象时为该字段设置了一个值,它也会被忽略。
- 该字段的默认表单部件是一个
DateInput
。管理中增加了一个 JavaScript 日历,以及“今天”的快捷方式。包含一个额外的invalid_date
错误信息键。 auto_now_add
、auto_now
和default
选项是相互排斥的。这些选项的任何组合都会导致错误。
- 一个日期,在 Python 中用一个
-
DateTimeField
- 一个日期和时间,在 Python 中用一个
datetime.datetime
实例表示。与DateField
一样,使用相同的额外参数。 - 该字段的默认表单部件是一个单独的
DateTimeInput
。管理中使用两个单独的TextInput
部件,并使用 JavaScript 快捷方式。
- 一个日期和时间,在 Python 中用一个
-
DecimalField
- 一个固定精度的十进制数,在 Python 中用一个
Decimal
实例来表示。它使用DecimalValidator
验证输入。 - 有两个 必要的 参数:
- DecimalField.max_digits
数字中允许的最大位数。请注意,这个数字必须大于或等于decimal_places
。 - DecimalField.decimal_places
与数字一起存储的小数位数。
- DecimalField.max_digits
- 一个固定精度的十进制数,在 Python 中用一个
-
DurationField
一个用于存储时间段的字段——在 Python 中用
timedelta
建模。当在 PostgreSQL 上使用时,使用的数据类型是interval
,在 Oracle 上使用的数据类型是INTERVAL DAY(9) TO SECOND(6)
。否则使用微秒的bigint
。 -
EmailField
一个
CharField
,使用EmailValidator
来检查该值是否为有效的电子邮件地址。 -
FileField
- 一个文件上传字段
- 有两个可选参数:
- FileField.upload_to
- 这个属性提供了一种设置上传目录和文件名的方式,可以有两种设置方式。在这两种情况下,值都会传递给
Storage.save()
方法。 - 如果你指定一个字符串值或一个
Path
,它可能包含strftime()
格式,它将被文件上传的日期/时间所代替(这样上传的文件就不会填满指定的目录)。 - 如果你使用的是默认的
FileSystemStorage
,这个字符串的值将被附加到你的MEDIA_ROOT
路径后面,形成本地文件系统中上传文件的存储位置。如果你使用的是不同的存储系统,请检查该存储系统的文档,看看它是如何处理upload_to
的。 upload_to
也可以是一个可调用对象,如函数。这个函数将被调用以获得上传路径,包括文件名。这个可调用对象必须接受两个参数,并返回一个 Unix 风格的路径(带斜线),以便传给存储系统。
- 这个属性提供了一种设置上传目录和文件名的方式,可以有两种设置方式。在这两种情况下,值都会传递给
- FileField.storage
- FileField.upload_to
-
FilePathField
一个
CharField
,其选择仅限于文件系统中某个目录下的文件名。有一些特殊的参数,其中第一个参数是 必须的。 -
FloatField
在 Python 中用一个
float
实例表示的浮点数。当localize
为False
时是NumberInput
否则,该字段的默认表单部件是TextInput
。 -
GenericIPAddressField
- IPv4 或 IPv6 地址,字符串格式(如
192.0.2.30
或2a02:42fe::4
)。该字段的默认表单部件是一个TextInput
。 - IPv6 地址规范化遵循 RFC 4291#section-2.2 第 2.2 节,包括使用该节第 3 段建议的 IPv4 格式,如
::fffff:192.0.2.0
。例如,2001:0::0:01
将被标准化为2001::1
,::fffff:0a0a:0a0a
将被标准化为::fffff:10.10.10.10
。所有字符都转换为小写。
- IPv4 或 IPv6 地址,字符串格式(如
-
ImageField
- 继承
FileField
的所有属性和方法,但也验证上传的对象是有效的图像。 - 除了
FileField
的特殊属性外,ImageField
也有height
和width
属性。 ImageField
实例在数据库中创建为varchar
列,默认最大长度为 100 个字符。与其他字段一样,你可以使用max_length
参数改变最大长度。- 该字段的默认表单部件是一个
ClearableFileInput
。
- 继承
-
IntegerField
- 一个整数。从
-2147483648
到2147483647
的值在 Django 支持的所有数据库中都是安全的。 - 它使用
MinValueValidator
和MaxValueValidator
根据默认数据库支持的值来验证输入。 - 当
localize
为False
时是NumberInput
否则,该字段的默认表单部件是TextInput
。
- 一个整数。从
-
JSONField
- 一个用于存储 JSON 编码数据的字段。在 Python 中,数据以其 Python 本地格式表示:字典、列表、字符串、数字、布尔值和
None
。 JSONField
在 MariaDB 10.2.7+、MySQL 5.7.8+、Oracle、PostgreSQL 和 SQLite(在 JSON1 扩展被启用的情况下)都支持。
- 一个用于存储 JSON 编码数据的字段。在 Python 中,数据以其 Python 本地格式表示:字典、列表、字符串、数字、布尔值和
-
PositiveBigIntegerField
就像一个
PositiveIntegerField
,但只允许在某一特定点下的值(依赖于数据库)。0
到9223372036854775807
的值在 Django 支持的所有数据库中都是安全的。 -
PositiveIntegerField
就像
IntegerField
一样,但必须是正值或零(0
)。从0
到2147483647
的值在 Django 支持的所有数据库中都是安全的。出于向后兼容的原因,接受0
的值。 -
PositiveSmallIntegerField
就像一个
PositiveIntegerField
,但只允许在某一特定(数据库依赖的)点下取值。0
到32767
的值在 Django 支持的所有数据库中都是安全的。 -
SlugField
- Slug 是一个报纸术语。slug 是一个简短的标签,只包含字母、数字、下划线或连字符。它们一般用于 URL 中。
- 像 CharField 一样,你可以指定
max_length
(也请阅读那一节中关于数据库可移植性和max_length
的说明)。如果没有指定max_length
,Django 将使用默认长度 50。 - 意味着将
Field.db_index
设置为True
。 - 基于其他值的值自动预填充一个 SlugField 通常是很有用的。 你可以在管理中使用
prepopulated_fields
来自动完成。 - 它使用
validate_slug
或validate_unicode_slug
进行验证。
-
SmallAutoField
就像一个
AutoField
,但只允许值在一定(依赖于数据库)的限制下。1
到32767
的值在 Django 支持的所有数据库中都是安全的。 -
SmallIntegerField
就像一个
IntegerField
,但只允许在某一特定(依赖于数据库的)点下取值。从-32768
到32767
的值在 Django 支持的所有数据库中都是安全的。 -
TextField
-
TimeField
-
URLField
- URL 的
CharField
,由URLValidator
验证。 - 该字段的默认表单部件是一个
URLInput
。 - 像所有的
CharField
子类一样,URLField
接受可选的max_length
参数。如果你没有指定max_length
参数,则使用默认的 200。
- URL 的
-
UUIDField
- 一个用于存储通用唯一标识符的字段。使用 Python 的
UUID
类。当在 PostgreSQL 上使用时,它存储在一个uuid
的数据类型中,否则存储在一个char(32)
中。 - 通用唯一标识符是
primary_key
的AutoField
的一个很好的替代方案。数据库不会为你生成 UUID,所以建议使用default
。
- 一个用于存储通用唯一标识符的字段。使用 Python 的
-
-
字段选项
-
null
- 如果是
True
, Django 将在数据库中存储空值为NULL
。默认为False
。 - 避免在基于字符串的字段上使用
null
,如CharField
和TextField
。如果一个基于字符串的字段有null=True
,这意味着它有两种可能的“无数据”值。NULL
,和空字符串。在大多数情况下,“无数据”有两种可能的值是多余的,Django 的惯例是使用空字符串,而不是NULL
。一个例外是当一个CharField
同时设置了unique=True
和blank=True
。在这种情况下,null=True
是需要的,以避免在保存具有空白值的多个对象时违反唯一约束。 - 无论是基于字符串的字段还是非字符串的字段,如果希望在表单中允许空值,还需要设置
blank=True
,因为null
参数只影响数据库的存储(参见blank
)。
- 如果是
-
blank
-
choices
一个 sequence 本身由正好两个项目的迭代项组成(例如
[(A,B),(A,B)...]
),作为该字段的选择。如果给定了选择,它们会被 模型验证 强制执行,默认的表单部件将是一个带有这些选择的选择框,而不是标准的文本字段。 -
db_column
- 这个字段要使用的数据库列名。如果没有给出列名,Django 将使用字段名。
- 如果你的数据库列名是 SQL 的保留字,或者包含了 Python 变量名中不允许的字符——特别是连字符——那也没关系。Django 会在幕后引用列名和表名。
-
db_index
如果是
True
,将为该字段创建数据库索引。 -
db_tablespace
如果这个字段有索引,那么要为这个字段的索引使用的 数据库表空间 的名称。默认是项目的
DEFAULT_INDEX_TABLESPACE
设置(如果有设置),或者是模型的db_tablespace
(如果有)。如果后端不支持索引的表空间,则忽略此选项。 -
default
- 该字段的默认值。可以是一个值或者是个可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。
- 默认值不能是一个可更改的对象(模型实例、
list
、set
等),因为对该对象同一实例的引用将被用作所有新模型实例的缺省值。相反,将所需的默认值包裹在一个可调用对象中。 lambda
不能用于default
等字段选项,因为它们不能被 迁移序列化。- 对于像
ForeignKey
这样映射到模型实例的字段,默认应该是它们引用的字段的值(默认是pk
除非to_field
被设置了),而不是模型实例。 - 当创建新的模型实例且没有为该字段提供值时,使用默认值。当字段是主键时,当字段设置为
None
时,也使用默认值。
-
editable
如果是
False
,该字段将不会在管理或任何其他ModelForm
中显示。在 模型验证 中也会跳过。默认为True
。 -
error_messages
error_messages
参数可以让你覆盖该字段引发的默认消息。传入一个与你想覆盖的错误信息相匹配的键值的字典。- 错误信息键包括
null
、blank
、invalid
、invalid_choice
、unique
和unique_for_date
。在下面的 字段类型 一节中为每个字段指定了额外的错误信息键。 - 这些错误信息通常不会传播到表单中。参见 有关模型的 error_messages 的注意事项。
-
help_text
- 额外的“帮助”文本,随表单控件一同显示。即便你的字段未用于表单,它对于生成文档也是很有用的。
- 请注意,在自动生成的表格中,这个值 不是 HTML 转义的。如果你愿意的话,你可以在
help_text
中加入 HTML。 - 或者你可以使用纯文本和
django.utils.html.escape()
来转义任何 HTML 特殊字符。确保你转义任何可能来自不受信任的用户的帮助文本,以避免跨站脚本攻击。
-
primary_key
- 如果设置为
True
,将该字段设置为该模型的主键。 - 如果你没有为模型中的任何字段指定
primary_key=True
,Django 会自动添加一个字段来保存主键,所以你不需要在任何字段上设置 primary_key=True,除非你想覆盖默认主键行为。自动创建的主键字段的类型可以在AppConfig.default_auto_field
中为每个应用程序指定,或者在DEFAULT_AUTO_FIELD
配置中全局指定。更多信息,请参阅 自动设置主键。 primary_key=True
意味着null=False
和unique=True
。一个对象只允许有一个主键。- 主键字段是只读的。如果您改变了现有对象的主键值,然后将其保存,则会在旧对象旁边创建一个新对象。
- 如果设置为
-
unique
- 如果设置为
True
,这个字段必须在整个表中保持值唯一。 - 这是在数据库级别和模型验证中强制执行的。如果你试图保存一个在
unique
字段中存在重复值的模型,模型的save()
方法将引发django.db.IntegrityError
。 - 除了
ManyToManyField
和OneToOneField
之外,该选项对所有字段类型有效。 - 请注意,当
unique
为True
时,你不需要指定db_index
,因为unique
意味着创建一个索引。
- 如果设置为
-
unique_for_date
- 将其设置为
DateField
或DateTimeField
的名称,要求该字段的日期字段值是唯一的。 - 例如,如果你的字段
title
有unique_for_date="pub_date"
,那么 Django 就不允许输入两条相同title
和pub_date
的记录。 - 请注意,如果将其设置为指向
DateTimeField
,则只考虑该字段的日期部分。此外,当USE_TZ
为True
时,检查将在对象保存时的 当前时区 中进行。 - 这在模型验证过程中由
Model.validate_unique()
强制执行,但在数据库级别上不执行。如果任何unique_for_date
约束涉及的字段不属于ModelForm
(例如,如果其中一个字段被列在exclude
中,或者有editable=False
),Model.validate_unique()
将跳过对该特定约束的验证。
- 将其设置为
-
unique_for_month
像
unique_for_date
一样,但要求字段对月份是唯一的。 -
unique_for_year
如
unique_fordate
和unique_formonth
。 -
verbose_name
字段的一个人类可读名称,如果没有给定详细名称,Django 会使用字段的属性名自动创建,并将下划线转换为空格。参见 详细字段名。
-
validators
要为该字段运行的验证器列表。更多信息请参见 验证器文档。
-
-
关系字段
- 分类
ForeignKey
:一对多,将字段定义在多的端中ManyToManyField
:多对多,将字段定义在两端中OneToOneField
:一对一,将字段定义在任意一端中
- 用一访问多
- 格式
对象.模型类小写_set
- 示例
grade.students_set
- 格式
- 用一访问一
- 格式
对象.模型类小写
- 示例
grade.students
- 格式
- 访问id
- 格式
对象.属性_id
- 示例
student.sgrade_id
- 格式
- 分类
-
-
创建模型类
-
学生类
1
2
3
4
5
6
7
8
9
10class Student(models.Model):
name = models.CharField(max_length=20)
sex = models.BooleanField()
content = models.CharField(max_length=20)
age = models.IntegerField()
grade = models.ForeignKey("Grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name -
班级类
1
2
3
4
5
6
7
8class Grade(models.Model):
name = models.CharField(max_length=20)
boyNum = models.IntegerField()
girlNum = models.IntegerField()
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name -
假数据
1
insert into myApp_grade(name,girlnum,boynum,isDelete) values("python01",10,50,0),("python02",4,34,0),("python03",12,60,0),("python04",3,75,0);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25insert into myApp_student(name,sex,content,isDelete,grade_id,age) values("薛延美",0,"我叫薛延美",0,4,20),
("陆彦旭",1,"我叫陆彦旭",0,4,30),
("范育宾",1,"我叫范育宾",0,4,40),
("向芳",0,"我叫向芳",0,4,18),
("阳亚霞",0,"我叫阳亚霞",0,4,16),
("孔玉",1,"我叫孔玉",0,4,50),
("孟林",1,"我叫孟林",0,3,60),
("孙雨",0,"我叫孙雨",0,3,70),
("郝路杰",1,"我叫郝路杰",0,3,33),
("夏明宇",1,"我叫夏明宇",0,3,34),
("王子衡",0,"我叫王子衡",0,3,28),
("韩俊",1,"我叫韩俊",0,2,4),
("申宝静",0,"我叫申宝静",0,2,6),
("孙狮勤",1,"我叫孙狮勤",0,2,20),
("李嘉熙",1,"我叫李嘉熙",0,2,10),
("许明宾",1,"我叫许明宾",0,2,54),
("陈俊伟",1,"我叫陈俊伟",0,3,45),
("何琪龙",1,"我叫何琪龙",0,4,66),
("武含",1,"我叫武含",0,3,23),
("田宝迎",0,"我叫田宝迎",0,2,44),
("李明志",1,"我叫李明志",0,1,23),
("武为民",0,"我叫武为民",0,1,55),
("徐兴达",0,"我叫徐兴达",0,1,51),
("唐李超",1,"我叫唐李超",0,1,33),
("陈致远",1,"我叫陈致远",0,1,90);
-
-
元选项
-
简介
- 在定义模型时内部添加
Meta
类,用来设置元信息
- 在定义模型时内部添加
-
db_table
- 定义数据库表名称,推荐使用小写字母,并且使用复数形式
-
ordering
- 对象的默认排序字段,获取对象的列表时使用
- 正序:
ordering = ["id"]
- 倒序:
ordering = ["-id"]
- 注意:排序会增加数据库的开销
-
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14class Student(models.Model):
name = models.CharField(max_length=20)
sex = models.BooleanField()
content = models.CharField(max_length=20)
age = models.IntegerField()
grade = models.ForeignKey("Grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
db_table = 'students'
ordering = ['-id']
-
模型成员
-
类型属性
-
objects
- 是Manager类型的对象,用于和数据库进行交互的
- 当定义模型时没有指定管理器,则Django会为模型自动添加一个名为objects的管理器
-
自定义模型管理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17class Student(models.Model):
# 自定义管理器
object1 = models.Manager()
name = models.CharField(max_length=20)
sex = models.BooleanField()
content = models.CharField(max_length=20)
age = models.IntegerField()
grade = models.ForeignKey("Grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
db_table = 'students'
ordering = ['-id']注意:当为模型指定管理器,Django不再为模型生成名为objects的管理器
-
自定义模型管理器类
- 作用
- 向管理器类中添加额外的方法
- 修改管理器中的返回原始查询集的方法,重写
get_queryset()
方法
- 示例:
1
2
3
4
5
6
7
8
9class StudentManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(isDelete=False)
class Student(models.Model):
# 自定义管理器
# object1 = models.Manager()
objects = StudentManager()
- 作用
-
创建对象
-
说明
当创建对象时,Django不会对数据库进行读写操作。调用
save()
方法才会与数据库交互,将数据保存到数据库中。 -
注意
__init__
方法已经在基类models.Model
类中使用,在定义模型类中无法使用 -
基本写法
1
2
3
4
5
6
7
8
9
10def addStudent(request):
stu = Student()
stu.name = "sunck"
stu.age = 18
stu.sex = True
stu.grade = Grade.objects.get(pk=1)
stu.content = "sunck is good man"
stus = Student.objects.all()
return render(request, 'myApp/students.html', {"stus": stus})以后不会采用
-
解决方案
-
方法一
在模型类中增加一个类方法(推荐)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27class StudentManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(isDelete=False)
class Student(models.Model):
# 自定义管理器
# object1 = models.Manager()
objects = StudentManager()
name = models.CharField(max_length=20)
sex = models.BooleanField()
content = models.CharField(max_length=20)
age = models.IntegerField()
grade = models.ForeignKey("Grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
db_table = 'students'
ordering = ['-id']
def create(cls, name, sex, age, content, grade):
return cls(name=name, sex=sex, age=age, content=content, grade=grade)1
2
3
4
5
6
7
8
9
10
11
12def addStudent(request):
# stu = Student()
# stu.name = "sunck"
# stu.age = 18
# stu.sex = True
# stu.grade = Grade.objects.get(pk=1)
# stu.content = "sunck is good man"
stu = Student.create("kaige", True, 17, "kaige is a nice man", Grade.objects.get(pk=2))
stu.save()
stus = Student.objects.all()
return render(request, 'myApp/students.html', {"stus": stus}) -
方法二
在自定义管理类中添加一个方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55from django.db import models
# Create your models here.
# 定义模型
class Grade(models.Model):
name = models.CharField(max_length=20)
boyNum = models.IntegerField()
girlNum = models.IntegerField()
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
db_table = 'grades'
class StudentManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(isDelete=False)
def create(self, name, sex, age, content, grade):
obj = self.model()
obj.name = name
obj.sex = sex
obj.age = age
obj.content = content
obj.grade = grade
return obj
class Student(models.Model):
# 自定义管理器
# object1 = models.Manager()
objects = StudentManager()
name = models.CharField(max_length=20)
sex = models.BooleanField()
content = models.CharField(max_length=20)
age = models.IntegerField()
grade = models.ForeignKey("Grade")
isDelete = models.BooleanField(default=False)
def __str__(self):
return self.name
class Meta:
db_table = 'students'
ordering = ['-id']
# @classmethod
# def create(cls, name, sex, age, content, grade):
# return cls(name=name, sex=sex, age=age, content=content, grade=grade)1
2
3
4
5
6
7
8
9
10
11
12
13def addStudent(request):
# stu = Student()
# stu.name = "sunck"
# stu.age = 18
# stu.sex = True
# stu.grade = Grade.objects.get(pk=1)
# stu.content = "sunck is good man"
# stu = Student.create("kaige", True, 17, "kaige is a nice man", Grade.objects.get(pk=2))
stu = Student.objects.create("kaishen", True, 19, "kaishen is a cool man", Grade.objects.get(pk=3))
stu.save()
stus = Student.objects.all()
return render(request, 'myApp/students.html', {"stus": stus})
-
-
模型查询
-
简介
- 从数据库中获取的对象集合
- 查询集可以有零个、一个或多个过滤器
- 过滤器基于所给的参数限制查询的结果
- 从SQL的角度,查询集合select语句等价,过滤器像where和limit等子句
-
查询集
- 在管理器上调用过滤器方法会得到查询集
- 查询集经过过滤器筛选后返回新的查询集,因此可以写成链式语法结构
- 惰性执行:创建查询集不会带来任何数据库的访问,直到调用数据时才会访问数据库
- 何时对查询集求值:
- 迭代
- 序列化
- 与if合用
-
返回查询集的过滤器
- 返回查询集的方法称为过滤器
all()
:获得所有数据filter()
:过滤出符合条件的数据filter(键1=值1, 键2=值2)
filter(键1=值1).filter(键2=值2)
exclude()
:过滤掉符合条件的数据order_by()
:排序values()
:一个对象构成一个字典,然后返回一个列表- 示例:
1
2
3
4
5
6def select1(request):
# stus = Student.objects.filter(age=20)
# stus = Student.objects.exclude(age=20)
# stus = Student.objects.order_by("age")
stus = Student.objects.order_by("-age")
return render(request, "myApp/students.html", {"stus": stus})
-
返回单个值的过滤器
get()
:返回单个满足条件的对象- 如果未找到会引发
模型类名.DoesNotExist
异常 - 如果多条数据被返回,会引发
模型类名.MultipleObjectsReturned
异常
- 如果未找到会引发
count()
:返回当前查询的总条数first()
:返回第一个对象last()
:返回最后一个对象exists()
:判断查询集是否有数据,如果有数据则返回True,否则返回False
-
-
字段查询
-
概述
- 实现where子句,作为方法filter、exculde、get的参数
- 语法
属性名称__比较运算符=值
- 注意:双下划线
- 对于外键:使用
属性名_id
表示外键的原始值
-
运算符
exact
:表示判等,大小写敏感contains
:是否包含,大小写敏感- 需求:表中content字段包含kaige的数据
- 实现:
1
2
3def select3(request):
stus = Student.objects.filter(content__contains="kaige")
return render(request, "myApp/students.html", {"stus":stus})
startswith
、endswith
:以value开头或者结尾,大小写敏感iexact
、icontains
、istartswith
、iendswith
:在前面加个i,表示不区分大小写isnull
、isnotnull
:是否为nullcontent__isnull=True
:获取content字段为null的数据content__isnotnull=True
:获取content字段不为null的数据
in
:是否包含在范围内- 需求:获取学生id值为2、4、6、8的学生
- 实现:
1
2
3def select3(request):
stus = Student.objects.filter(pk__in=[2,4,6,8])
return render(request, "myApp/students.html", {"stus":stus})
gt
、gte
、lt
、lte
:大于、大于等于、小于、小于等于- 需求:获取年龄大于等于20的所有学生
- 实现:
1
2
3def select3(request):
stus = Student.objects.filter(age__gte=20)
return render(request, "myApp/students.html", {"stus":stus})
year
、month
、day
、week_day
、hour
、minute
、second
:对日期类型的属性进行运算filter(createtime__year=2018)
filter(createtime__gt=date(2018,5,9))
-
跨关联关系的查询
- 处理join查询
- 语法:
模型类名小写__属性名__比较运算符
- 注意:可以没有
__比较运算符
,表示等于,结果同inner join
- 语法:
- 需求
- 描述中带有【薛延美】的学生属于哪个班级
- 实现
1
g = Grade.objects.filter(student__content__contains="薛延美")
- 处理join查询
-
查询的快捷方式
- pk:pk代表primary key,默认的主键是id
-
聚合函数
- 使用
aggregate()
函数返回聚合函数的值 - 示例:
1
2
3
4
5
6
7
8from django.db.models import Sum
def select4(request):
ageSum = Student.objects.aggregate(Sum("age"))
print("***********************", ageSum)
stus = Student.objects.all()
return render(request, "myApp/students.html", {"stus": stus})
- 使用
-
限制查询集
- 查询集返回列表,可以使用下标的方式进行限制,等同于SQL中的limit和offset子句
- 注意:
- 不支持负数索引
- 使用下标后会得到一个新的查询集,不会立即执行查询集
- 如果获取一个对象,直接使用[下标]
1
stus = Student.objects.all()[5:10]
-
F对象
- 可以使用模型的字段A与字段B进行比较,如果字段A写在了等到左侧,则字段B写在等号右侧且需要通过F对象来构造
- 需求:获取班级中男生个数多于女生个数的班级
1
2
3
4
5
6from django.db.models import F
def select6(request):
grades = Grade.objects.filter(boyNum__gt=F("girlNum"))
return render(request, 'myApp/grades.html', {'grades': grades}) - 需求:获取班级中男生个数多于女生个数2倍的班级
1
2
3
4
5
6from django.db.models import F
def select6(request):
grades = Grade.objects.filter(boyNum__gt=F("girlNum")*2)
return render(request, 'myApp/grades.html', {'grades': grades})Django支持对F对象使用数学运算
- 需求:获取学生没有被删除的班级
> F对象还可以写做`模型类(小写)__属性名`进行关联查询1
2
3
4
5
6from django.db.models import F
def select6(request):
grades = Grade.objects.filter(isDelete=F("student__isDelete"))
return render(request, 'myApp/grades.html', {'grades': grades})- 对于
date
、time
、dateTime
字段,可以与timedelta()
进行运算。
-
Q对象
- 过滤器的方法中关键字参数查询,会合并成and进行
- 需要进行or查询,使用Q对象
- 逻辑与
1
2
3def select7(request):
stus = Student.objects.filter(age__gte=20, age__lte=50)
return render(request, "myApp/students.html", {"stus":stus})1
2
3
4
5
6from django.db.models import Q
def select7(request):
stus = Student.objects.filter(Q(age__gte=20) & Q(age__lte=50))
return render(request, "myApp/students.html", {"stus": stus}) - 逻辑或
1
2
3
4
5
6from django.db.models import Q
def select7(request):
stus = Student.objects.filter(Q(age__lte=20) | Q(age__gte=50))
return render(request, "myApp/students.html", {"stus": stus}) - 逻辑非
1
2
3
4
5
6from django.db.models import Q
def select7(request):
stus = Student.objects.filter(~Q(age__lte=20))
return render(request, "myApp/students.html", {"stus": stus})
-
模型关系
-
1-1
- 使用场景:表的字段太多,需要拆分
- 案例类
- 人
1
2
3class Person(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField() - 身份证
1
2
3
4
5
6class IDCard(models.Model):
cardID = models.CharField(max_length=18)
sex = models.BooleanField()
# 关系存放在哪张表里都可以
# 绑定身份证与人的一对一关系,默认情况下,当人被删除,与人绑定的身份证也就删除了,这个可以使用on_delete来进行调整
person = models.OneToOneField(Person)on_delete
models.CASCADE
:默认值models.PROTECT
:保护模式models.SET_NULL
:置空模式models.SET_DEFAULT
:置默认值models.SET()
:删除的时候重新动态指定一个实体访问对象
- 主表从表:声明关系的表是从表
- 人
- 级联数据获取
从获取主1
2
3def idcard(request, cid):
card = IDCard.objects.get(pk=cid)
return HttpResponse(card.cardID + '--' + card.person.name)关系是直接声明的,它是一个显性属性
主获取从1
2
3def person(request, pid):
per = Person.objects.get(pk=pid)
return HttpResponse(per.name + '--' + per.idcard.cardID)关系字段是隐性属性,
对象.关系模型名(小写)
- 删除
1
2
3
4
5
6
7
8
9
10def delPerson(request, pid):
per = Person.objects.get(pk=pid)
per.delete()
return HttpResponse(per.name + '删除成功')
def delIdCard(request, cid):
card = IDCard.objects.get(pk=cid)
card.delete()
return HttpResponse(card.cardID + '删除成功')
-
1-n
-
m-n
- 原理:底层是通过两个外键实现的,两个外键存在于关系表中
- 案例表
1
2
3
4
5
6class Buyer(models.Model):
name = models.CharField(max_length=20)
level = models.IntegerField(default=1)
def __str__(self):
return self.name1
2
3
4
5
6
7
8
9class Goods(models.Model):
name = models.CharField(max_length=20)
price = models.FloatField()
num = models.IntegerField()
# 形成多对多关系, 外键写在哪张表里都可以
buyers = models.ManyToManyField(Buyer)
def __str__(self):
return self.name会自动生成一张外键管理表
- 产生关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23def addBuyer(request, bid):
buyer = Buyer()
buyer.name = "用户" + bid
buyer.save()
return HttpResponse(buyer.name + "创建成功")
def addGoods(request, gid):
goods = Goods()
goods.name = "商品" + gid
goods.price = 1
goods.num = 10
goods.save()
return HttpResponse(goods.name + "创建成功")
def addGoodsToBuyer(request, bid, gid):
goods = Goods.objects.get(pk=gid)
buyer = Buyer.objects.get(pk=bid)
# 形成关系
goods.buyers.add(buyer)
goods.save()
return HttpResponse(buyer.name + "购买了" + goods.name) - 获取
- 通过商品获取购买者(从获取主)
1
2
3
4
5def getBuyersFromGoods(request, gid):
goods = Goods.objects.get(pk=gid)
buyers = goods.buyers.all()
print(buyers)
return HttpResponse("找到了所有买的用户")显性属性,一个集合,类似
model.Manager
,也可以进行filter等 - 通过购买者获取所有的商品(主获取从)
1
2
3
4
5def getGoodsFromBuyer(request, bid):
buyer = Buyer.objects.get(pk=bid)
goodsList = buyer.goods_set.all()
print(goodsList)
return HttpResponse("找到了该用户买的所有商品")隐性属性
对象.关联对象(小写)_set.all、filter
等
- 通过商品获取购买者(从获取主)
- 删除:删除数据的时候会删除自己的数据和关系表中的数据
1
2
3
4
5
6
7
8
9
10def delBuyer(request, bid):
buyer = Buyer.objects.get(pk=bid)
buyer.delete()
return HttpResponse('删除了' + buyer.name)
def delGoods(request, gid):
goods = Goods.objects.get(pk=gid)
goods.delete()
return HttpResponse('删除了' + goods.name)
-
模型继承
- Django中的数据库提供了一个非常不错的功能,就是支持models的面向对象,可以在models中添加Meta类指定是否抽象,然后继承。
- 默认模型是允许继承的,但是默认的继承处理方式不是很合理
- 默认在父类中定义的字段会在父类的表中,子类的数据通用部分会存在父表中,子类特有的数据会在子表中,子类通过外键进行级联
- 默认方式比较垃圾,效率比较低
- 数据库优化策略
- 避免关系过多级联
- 避免IO
- 示例:
1
2
3
4
5
6
7
8
9
10
11class Animal(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
class Dog(Animal):
a = models.CharField(max_length=10)
class Cat(Animal):
b = models.CharField(max_length=10)
- 开发中,需要将父类抽象化
- 在元信息中添加
abstract=True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Animal(models.Model):
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta:
# 将该类抽象化,将父类中的字段直接放入子类对应的表中,并且不会生成该模型对应的表
abstract = True
class Dog(Animal):
a = models.CharField(max_length=10)
class Cat(Animal):
b = models.CharField(max_length=10)
- 在元信息中添加
-