Django-模型

概述

  • Django对各种数据库都提供了良好的支持
  • Django为这些数据库提供了统一的调用接口API,我们可以根据业务需求选择使用不同的数据库

配置MySQL

  • DATABASES 做如下修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql',
    'NAME': '数据库名',
    'USER': '用户名',
    'PASSWORD': '密码',
    'HOST': '主机',
    'PORT': '端口'
    }
    }

ORM

  • 概述

    • 对象-关系-映射
    • 将对象的操作自动转换成对应数据库语句
  • 任务

    • 根据类生成表结构
    • 将对象、列表的操作转换为SQL语句
    • 将SQL查询到的结果转换为对象、列表
  • 优点

    • 极大的减少开发人员的工作量,不需要面对因数据库变更而导致代码无效
  • 图解

    ORM

定义模型

  • 模型、属性、表、字段间的关系

    • 一个模型在数据库中对应一张表,在模型中定义的属性,对应该模型对照表中的一个字段
  • 定义属性

    • 概述

      • django根据属性的类型确定以下信息
        • 当前选择的数据库支持字段的类型
        • 渲染管理表单时使用的默认html控件
        • 在管理站点最低限度的验证
      • django会为表增加自动增长的主键列,每个模型只能有一个主键列,如果使用选项设置某属性为主键列后,则django不会再生成默认的主键列
      • 属性命名限制
        • 不能是python的保留关键字
        • 由于django的查询方式,不允许使用连续的下划线
      • 定义属性时,需要字段类型,字段类型被定义在django.db.models.fields目录下,为了方便使用,被导入到django.db.models
      • 使用方式
        • 导入from django.db import models
        • 通过models.Field创建字段类型的对象,赋值给属性
    • 逻辑删除

      • 对于重要数据都做逻辑删除,不做物理删除,实现方法是定义isDelete属性,类型为BooleanField,默认值为False
    • 字段类型

      • AutoField

        一个 IntegerField,根据可用的 ID 自动递增。你通常不需要直接使用它;如果你没有指定,主键字段会自动添加到你的模型中。参见 自动设置主键

      • BigAutoField

        一个 64 位整数,与 AutoField 很相似,但保证适合 19223372036854775807 的数字。

      • BigIntegerField

        一个 64 位的整数,和 IntegerField 很像,只是它保证适合从 -92233720368547758089223372036854775807 的数字。该字段的默认表单部件是一个 NumberInput

      • BinaryField

        一个用于存储原始二进制数据的字段。可以指定为 bytesbytearraymemoryview

      • 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_addauto_nowdefault 选项是相互排斥的。这些选项的任何组合都会导致错误。
      • DateTimeField
        • 一个日期和时间,在 Python 中用一个 datetime.datetime 实例表示。与 DateField 一样,使用相同的额外参数。
        • 该字段的默认表单部件是一个单独的 DateTimeInput。管理中使用两个单独的 TextInput 部件,并使用 JavaScript 快捷方式。
      • DecimalField
        • 一个固定精度的十进制数,在 Python 中用一个 Decimal 实例来表示。它使用 DecimalValidator 验证输入。
        • 有两个 必要的 参数:
          • DecimalField.max_digits
            数字中允许的最大位数。请注意,这个数字必须大于或等于 decimal_places
          • DecimalField.decimal_places
            与数字一起存储的小数位数。
      • 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
            • 一个存储对象,或是一个返回存储对象的可调用对象。它处理你的文件的存储和检索。参见 管理文件,了解如何提供这个对象。
            • 该字段的默认表单部件是一个 ClearableFileInput
            • 如果你想检索上传文件的盘上文件名,或者文件的大小,可以分别使用 namesize 属性;关于可用属性和方法的更多信息,请参见 File 类参考和 管理文件 主题指南。
      • FilePathField

        一个 CharField,其选择仅限于文件系统中某个目录下的文件名。有一些特殊的参数,其中第一个参数是 必须的

      • FloatField

        在 Python 中用一个 float 实例表示的浮点数。当 localizeFalse 时是 NumberInput 否则,该字段的默认表单部件是 TextInput

      • GenericIPAddressField
        • IPv4 或 IPv6 地址,字符串格式(如 192.0.2.302a02: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。所有字符都转换为小写。
      • ImageField
        • 继承 FileField 的所有属性和方法,但也验证上传的对象是有效的图像。
        • 除了 FileField 的特殊属性外, ImageField 也有 heightwidth 属性。
        • ImageField 实例在数据库中创建为 varchar 列,默认最大长度为 100 个字符。与其他字段一样,你可以使用 max_length 参数改变最大长度。
        • 该字段的默认表单部件是一个 ClearableFileInput
      • IntegerField
        • 一个整数。从 -21474836482147483647 的值在 Django 支持的所有数据库中都是安全的。
        • 它使用 MinValueValidatorMaxValueValidator 根据默认数据库支持的值来验证输入。
        • localizeFalse 时是 NumberInput 否则,该字段的默认表单部件是 TextInput
      • JSONField
        • 一个用于存储 JSON 编码数据的字段。在 Python 中,数据以其 Python 本地格式表示:字典、列表、字符串、数字、布尔值和 None
        • JSONField 在 MariaDB 10.2.7+、MySQL 5.7.8+、Oracle、PostgreSQL 和 SQLite(在 JSON1 扩展被启用的情况下)都支持。
      • PositiveBigIntegerField

        就像一个 PositiveIntegerField,但只允许在某一特定点下的值(依赖于数据库)。09223372036854775807 的值在 Django 支持的所有数据库中都是安全的。

      • PositiveIntegerField

        就像 IntegerField 一样,但必须是正值或零( 0 )。从 02147483647 的值在 Django 支持的所有数据库中都是安全的。出于向后兼容的原因,接受 0 的值。

      • PositiveSmallIntegerField

        就像一个 PositiveIntegerField,但只允许在某一特定(数据库依赖的)点下取值。032767 的值在 Django 支持的所有数据库中都是安全的。

      • SlugField
        • Slug 是一个报纸术语。slug 是一个简短的标签,只包含字母、数字、下划线或连字符。它们一般用于 URL 中。
        • 像 CharField 一样,你可以指定 max_length (也请阅读那一节中关于数据库可移植性和 max_length 的说明)。如果没有指定 max_length,Django 将使用默认长度 50。
        • 意味着将 Field.db_index 设置为 True
        • 基于其他值的值自动预填充一个 SlugField 通常是很有用的。 你可以在管理中使用 prepopulated_fields 来自动完成。
        • 它使用 validate_slugvalidate_unicode_slug 进行验证。
      • SmallAutoField

        就像一个 AutoField,但只允许值在一定(依赖于数据库)的限制下。132767 的值在 Django 支持的所有数据库中都是安全的。

      • SmallIntegerField

        就像一个 IntegerField,但只允许在某一特定(依赖于数据库的)点下取值。从 -3276832767 的值在 Django 支持的所有数据库中都是安全的。

      • TextField
        • 一个大的文本字段。该字段的默认表单部件是一个 Textarea
        • 如果你指定了 max_length 属性,它将反映在自动生成的表单字段的 Textarea 部件中。但是,它并没有在模型或数据库层面被强制执行。使用一个 CharField 来实现。
      • TimeField
        • 一个时间,在 Python 中用 datetime.time 实例表示。接受与 DateField 相同的自动填充选项。
        • 该字段默认的表单部件t是一个 TimeInput。管理中添加了一些 JavaScript 快捷方式。
      • URLField
      • UUIDField
        • 一个用于存储通用唯一标识符的字段。使用 Python 的 UUID 类。当在 PostgreSQL 上使用时,它存储在一个 uuid 的数据类型中,否则存储在一个 char(32) 中。
        • 通用唯一标识符是 primary_keyAutoField 的一个很好的替代方案。数据库不会为你生成 UUID,所以建议使用 default
    • 字段选项

      • null
        • 如果是 True, Django 将在数据库中存储空值为 NULL。默认为 False
        • 避免在基于字符串的字段上使用 null,如 CharFieldTextField。如果一个基于字符串的字段有 null=True,这意味着它有两种可能的“无数据”值。NULL,和空字符串。在大多数情况下,“无数据”有两种可能的值是多余的,Django 的惯例是使用空字符串,而不是 NULL。一个例外是当一个 CharField 同时设置了 unique=Trueblank=True。在这种情况下,null=True 是需要的,以避免在保存具有空白值的多个对象时违反唯一约束。
        • 无论是基于字符串的字段还是非字符串的字段,如果希望在表单中允许空值,还需要设置 blank=True,因为 null 参数只影响数据库的存储(参见 blank )。
      • blank
        • 如果是 True ,该字段允许为空。默认为 False
        • 注意,这与 null 不同。 null 纯属数据库相关,而 blank 则与验证相关。如果一个字段有 blank=True,表单验证将允许输入一个空值。如果一个字段有 blank=False,则该字段为必填字段。
      • choices

        一个 sequence 本身由正好两个项目的迭代项组成(例如 [(A,B),(A,B)...] ),作为该字段的选择。如果给定了选择,它们会被 模型验证 强制执行,默认的表单部件将是一个带有这些选择的选择框,而不是标准的文本字段。

      • db_column
        • 这个字段要使用的数据库列名。如果没有给出列名,Django 将使用字段名。
        • 如果你的数据库列名是 SQL 的保留字,或者包含了 Python 变量名中不允许的字符——特别是连字符——那也没关系。Django 会在幕后引用列名和表名。
      • db_index

        如果是 True,将为该字段创建数据库索引。

      • db_tablespace

        如果这个字段有索引,那么要为这个字段的索引使用的 数据库表空间 的名称。默认是项目的 DEFAULT_INDEX_TABLESPACE 设置(如果有设置),或者是模型的 db_tablespace (如果有)。如果后端不支持索引的表空间,则忽略此选项。

      • default
        • 该字段的默认值。可以是一个值或者是个可调用的对象,如果是个可调用对象,每次实例化模型时都会调用该对象。
        • 默认值不能是一个可更改的对象(模型实例、listset 等),因为对该对象同一实例的引用将被用作所有新模型实例的缺省值。相反,将所需的默认值包裹在一个可调用对象中。
        • lambda 不能用于 default 等字段选项,因为它们不能被 迁移序列化
        • 对于像 ForeignKey 这样映射到模型实例的字段,默认应该是它们引用的字段的值(默认是 pk 除非 to_field 被设置了),而不是模型实例。
        • 当创建新的模型实例且没有为该字段提供值时,使用默认值。当字段是主键时,当字段设置为 None 时,也使用默认值。
      • editable

        如果是 False,该字段将不会在管理或任何其他 ModelForm 中显示。在 模型验证 中也会跳过。默认为 True

      • error_messages
        • error_messages 参数可以让你覆盖该字段引发的默认消息。传入一个与你想覆盖的错误信息相匹配的键值的字典。
        • 错误信息键包括 nullblankinvalidinvalid_choiceuniqueunique_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=Falseunique=True。一个对象只允许有一个主键。
        • 主键字段是只读的。如果您改变了现有对象的主键值,然后将其保存,则会在旧对象旁边创建一个新对象。
      • unique
        • 如果设置为 True,这个字段必须在整个表中保持值唯一。
        • 这是在数据库级别和模型验证中强制执行的。如果你试图保存一个在 unique 字段中存在重复值的模型,模型的 save() 方法将引发 django.db.IntegrityError
        • 除了 ManyToManyFieldOneToOneField 之外,该选项对所有字段类型有效。
        • 请注意,当 uniqueTrue 时,你不需要指定 db_index,因为 unique 意味着创建一个索引。
      • unique_for_date
        • 将其设置为 DateFieldDateTimeField 的名称,要求该字段的日期字段值是唯一的。
        • 例如,如果你的字段 titleunique_for_date="pub_date",那么 Django 就不允许输入两条相同 titlepub_date 的记录。
        • 请注意,如果将其设置为指向 DateTimeField,则只考虑该字段的日期部分。此外,当 USE_TZTrue 时,检查将在对象保存时的 当前时区 中进行。
        • 这在模型验证过程中由 Model.validate_unique() 强制执行,但在数据库级别上不执行。如果任何 unique_for_date 约束涉及的字段不属于 ModelForm (例如,如果其中一个字段被列在exclude中,或者有 editable=False ), Model.validate_unique() 将跳过对该特定约束的验证。
      • unique_for_month

        unique_for_date 一样,但要求字段对月份是唯一的。

      • unique_for_year

        unique_fordateunique_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
      10
      class 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
      8
      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
    • 假数据

      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
      25
      insert 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
      14
      class 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
      17
      class 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
        9
        class 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
    10
    def 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
      27
      class 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']

      @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
      def 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
      55
      from 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
      13
      def 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
        6
        def 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
          3
          def select3(request):
          stus = Student.objects.filter(content__contains="kaige")
          return render(request, "myApp/students.html", {"stus":stus})
      • startswithendswith:以value开头或者结尾,大小写敏感
      • iexacticontainsistartswithiendswith:在前面加个i,表示不区分大小写
      • isnullisnotnull:是否为null
        • content__isnull=True:获取content字段为null的数据
        • content__isnotnull=True:获取content字段不为null的数据
      • in:是否包含在范围内
        • 需求:获取学生id值为2、4、6、8的学生
        • 实现:
          1
          2
          3
          def select3(request):
          stus = Student.objects.filter(pk__in=[2,4,6,8])
          return render(request, "myApp/students.html", {"stus":stus})
      • gtgteltlte:大于、大于等于、小于、小于等于
        • 需求:获取年龄大于等于20的所有学生
        • 实现:
          1
          2
          3
          def select3(request):
          stus = Student.objects.filter(age__gte=20)
          return render(request, "myApp/students.html", {"stus":stus})
      • yearmonthdayweek_dayhourminutesecond:对日期类型的属性进行运算
        • filter(createtime__year=2018)
        • filter(createtime__gt=date(2018,5,9))
    • 跨关联关系的查询
      • 处理join查询
        • 语法:模型类名小写__属性名__比较运算符
        • 注意:可以没有__比较运算符,表示等于,结果同inner join
      • 需求
        • 描述中带有【薛延美】的学生属于哪个班级
      • 实现
        1
        g = Grade.objects.filter(student__content__contains="薛延美")
    • 查询的快捷方式
      • pk:pk代表primary key,默认的主键是id
    • 聚合函数
      • 使用aggregate()函数返回聚合函数的值
      • 示例:
        1
        2
        3
        4
        5
        6
        7
        8
        from 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
        6
        from 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
        6
        from 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对象使用数学运算

      • 需求:获取学生没有被删除的班级
      1
      2
      3
      4
      5
      6
      from django.db.models import F


      def select6(request):
      grades = Grade.objects.filter(isDelete=F("student__isDelete"))
      return render(request, 'myApp/grades.html', {'grades': grades})
      > F对象还可以写做`模型类(小写)__属性名`进行关联查询
      • 对于datetimedateTime字段,可以与timedelta()进行运算。
    • Q对象
      • 过滤器的方法中关键字参数查询,会合并成and进行
      • 需要进行or查询,使用Q对象
      • 逻辑与
        1
        2
        3
        def 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
        6
        from 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
        6
        from 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
        6
        from 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
            3
            class Person(models.Model):
            name = models.CharField(max_length=20)
            age = models.IntegerField()
          • 身份证
            1
            2
            3
            4
            5
            6
            class 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
          3
          def idcard(request, cid):
          card = IDCard.objects.get(pk=cid)
          return HttpResponse(card.cardID + '--' + card.person.name)

          关系是直接声明的,它是一个显性属性
          主获取从

          1
          2
          3
          def 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
          10
          def 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
          6
          class Buyer(models.Model):
          name = models.CharField(max_length=20)
          level = models.IntegerField(default=1)

          def __str__(self):
          return self.name
          1
          2
          3
          4
          5
          6
          7
          8
          9
          class 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
          23
          def 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
            5
            def getBuyersFromGoods(request, gid):
            goods = Goods.objects.get(pk=gid)
            buyers = goods.buyers.all()
            print(buyers)
            return HttpResponse("找到了所有买的用户")

            显性属性,一个集合,类似model.Manager,也可以进行filter等

          • 通过购买者获取所有的商品(主获取从)
            1
            2
            3
            4
            5
            def 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
          10
          def 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
        11
        class 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
        15
        class 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)
本文结束 感谢您的阅读
正在加载今日诗词....