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查询到的结果转换为对象、列表
 
- 
优点- 极大的减少开发人员的工作量,不需要面对因数据库变更而导致代码无效
 
- 
图解![ORM]() 
定义模型
- 
模型、属性、表、字段间的关系- 一个模型在数据库中对应一张表,在模型中定义的属性,对应该模型对照表中的一个字段
 
- 
定义属性- 
概述- 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:是否为null- content__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=True1 
 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)
 
- 在元信息中添加
 
- 
