Django 学习笔记之模型高级用法

[TOC]html

1 复杂的字段类型

通过前面的学习,咱们知道模型的字段类型一方面是指定数据库表的列名称和数据类型,另外一方面决定 HTML 中的表单标签类型。前端

1.1 整数类型的区别

Django 的整数类型有三个,分别是 IntegerFieldBigIntegerFieldSmallIntegerField。这三个字段区别在于取值范围。IntegerField 在 Django 全部支持的数据库中,合法取值范围是 -2147483648 到 2147483647。而 BigIntegerField 是一个 64 位整数,它容许的值范围是 -9223372036854775808 到 9223372036854775807。因此在数据库迁移的时候,特别数据库中有 Sqlite 时,要更加注意数字的取值范围。SmallIntegerField 取值范围是 -32768 到 32767。python

1.2 自增类型的区别

AutoFiledBigAutoFiled 都是自增类型,它们都是由整数类型演化而来。AutoFiled 是一个根据实际 ID 自动增加的 IntegerField。一般不须要直接使用它,若是表中没有设置主键时,Django 将会自动添加一个自增主键。BigAutoField 其实也是一个 BigIntegerField,但它支持 ID 自动增加。因此它的取值范围不能为负数和零了。正则表达式

1.3 时间类型

DateField 和 DateTimeField 中的两个重要属性 auto_nowauto_now_add 默认值都是 Flase。 设置 auto_now 或者 auto_now_add 的值为 True,间接给该字段设置了 editable=False 和 blank=True 。给参数赋值须要传递一个 datetime.date 对象。若是时间是一串字符串,则转化为 date 对象。数据库

DateField 支持输入值的形式以下:django

['%Y-%m-%d',      # '2006-10-25'
 '%m/%d/%Y',      # '10/25/2006'
 '%m/%d/%y']      # '10/25/06'

DateTimeField 支持输入值的形式以下:编程

['%b %d %Y',      # 'Oct 25 2006'
 '%b %d, %Y',     # 'Oct 25, 2006'
 '%d %b %Y',      # '25 Oct 2006'
 '%d %b, %Y',     # '25 Oct, 2006'
 '%B %d %Y',      # 'October 25 2006'
 '%B %d, %Y',     # 'October 25, 2006'
 '%d %B %Y',      # '25 October 2006'
 '%d %B, %Y']     # '25 October, 2006'

1.4 FilePathField

该字段是用于保存文件路径信息的。默认最大长度为 100,当可经过 max_length 参数自定义。它包含几个重要的参数:服务器

path:必传参数。记录目录或者文件的绝对路径。例如:/home/monkey match:可选参数,它是一个正则表达式,主要用于匹配过滤出文件名。 recursive:可选参数,表示是否包含子目录。默认值为 Flase。 allow_files:可选参数,表示是否将文件名包括在内,默认值为 True。 allow_folders:可选参数,表示是否将目录名包括在内默认值为 Flase。函数

Django 规定 allow_files 和 allow_folders 二者之间必须有一个值为 True。学习

1.5 FileField

上传文件字段,常见于表单中。通常而言,文件都是保存在服务器的硬盘中。所以,该字段在数据库中实际上是一个字符串类型,默认最大长度100,能够经过max_length参数自定义。

FileField 有两个重要的可选参数:upload_tostorage

  • upload_to upload_to 是指定文件上传的目录。用法以下:
class MyModel(models.Model):
    # 文件上传到 MEDIA_ROOT/uploads
    upload = models.FileField(upload_to='uploads/')
    # 或者
    # 文件上传到 MEDIA_ROOT/uploads/2015/01/30
    upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

其中 MEDIA_ROOT 是在 settings.py 中设置,表示上传文件的根目录。另外还须要设置 MEDIA_URL, 它表示上传文件对外能访问的 url 地址。

  • Storage Storage 是一个文件操做对象。它提供 size(path)、open(path).read()、delete(path)、exists(path)等方法来操做文件。

1.6 ImageField

保存图像文件的字段。ImageField 用法跟 FileField 相似。除了须要在 seeting.py 中增长相关配置,还都拥有共同的 upload_to 字段选项。

它还有额外的可选参数:一个是 height_field,表示保存图片的高度。 另外一个是 width_field,表示保存图片的宽度。

2 关系字段

以前文章讲了三种关系字段的类型、定义、做用。今天讲下其中的一些字段选项。

2.1 ForeignKey

2.1.1on_delete

在 Django 2.0 中,设置外键时须要添加一个 on_delete 选项。外键自己涉及到两个表的数据,何况外键在数据库中是有约束行为。因此 on_delete 参数是 Django 模拟 SQL 约束的行为。

on_delete 有几个可选值:

  • CASCADE:这就是默认的选项,级联删除,你无需显性指定它。
  • PROTECT: 保护模式,若是采用该选项,删除的时候,会抛出 ProtectedError 错误。
  • SET_NULL: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,容许为空。
  • SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,因此定义外键的时候注意加上一个默认值。
  • SET(): 自定义对应的实体的值。

2.1.2limit_choices_to

该参数用于限制外键所能关联的对象,只能用于 Django 的 ModelForm(Django的表单模块)和 admin 后台,对其它场合无限制功能。该值接受是一个字典、返回一个字典的函数

db_constraint 默认状况下,这个参数被设为 True,表示遵循数据库约束。若是设为 False,那么将没法保证数据的完整性和合法性。

2.1.3related_name

用于关联对象反向引用模型的名称。主要用于反向查询,即外键源模型实例经过管理器返回第一个模型的全部实例。

默认状况下,这个管理器的名字为 foo_set,其中 foo 是源模型名字的小写。例如:

# 在终端下使用 Django
>>>b = Book.objects.get(id=1)
# 其中 entry_set 为默认的 related_name
>>>b.entry_set.all() 
>>>b.entry_set.filter(headline__contains='天龙八部')
>>>b.entry_set.count()

若是咱们设置 related_name='novels',那么上面的代码将变为:

# 在终端下使用 Django
>>>b = Book.objects.get(id=1)
# 其中 entry_set 为默认的 related_name
>>>b.novels.all() 
>>>b.novels.filter(headline__contains='天龙八部')
>>>b.novels.count()

2.1.4related_query_name

反向查询的关系查询集名称。用于从目标模型反向过滤模型对象的名称。具体用法以下:

class Tag(models.Model):
    article = models.ForeignKey(
        Article,
        on_delete=models.CASCADE,
        related_name="tags",
        related_query_name="tag",
    )
    name = models.CharField(max_length=255)

# 如今可使用 tag做为查询名
Article.objects.filter(tag__name="important")

3 字段选项

字段选项是给每一个 Field 指定一些属性。

db_column: 指定当前数据库表中该字段的列名。若是没有指定,Django 默认将 Field 名做为字段名。

db_index: 若是赋值为 True, 将会为这个字段建立数据库索引。

db_tablespace:若是该字段已经设置了索引,db_tablespace 用于指定字段索引的数据库表空间的名字。另外还须要看使用的数据库支不支持表空间。若是不支持,该参数设置没有效果。

editable:设置该字段是否能被编辑,默认是 True。若是设为 False , 这个字段将不会出如今 admin 或者其余 ModelForm 中。 同时也会跳过 模型验证 。

error_messages:用于自定义错误提示信息。参数接受的是字典类型的值。字典的 key 能够是 null, blank, invalid, invalid_choice, unique, 和 unique_for_dat 其中的一个。

help_text:用于前端页面上显示提示信息。要确保页面不存在 XXS 漏洞,须要使用django.utils.html.escape() 对内容进行转义。

unique_for_date:设置为 DateField 或者 DateTimeField 字段的名字,表示要求该字段对于相应的日期字段值是惟一的。例如,字段 title 设置了 unique_for_date="pub_date" ,那么Django将不会容许在同一 pub_date 的两条记录的 title 相同。

unique_for_month:用法跟 unique_for_date 相似。

unique_for_year:用法跟 unique_for_date 相似。

verbose_name:为字段设置别名。对于每个字段类型,除了 ForeignKey、ManyToManyField和 OneToOneField 这三个特殊的关系类型,其第一可选位置参数都是 verbose_name。若是用户没有定义该选项, Django会自动将自动建立,内容是该字段属性名中的下划线转换为空格的结果。

好比这个例子中描述名是 person's first name:

first_name = models.CharField("person's first name", max_length=30)

而没有主动设置时,则是 first name:

first_name = models.CharField(max_length=30)

对于外键、多对多和一对一字字段,因为第一个参数须要用来指定关联的模型。所以必须用关键字参数 verbose_name 来明确指定。以下:

poll = models.ForeignKey(
    Poll,
    on_delete=models.CASCADE,
    verbose_name="the related poll",
)
sites = models.ManyToManyField(Site, verbose_name="list of sites")
place = models.OneToOneField(
    Place,
    on_delete=models.CASCADE,
    verbose_name="related place",
)

另外 verbose_name 不用大写首字母,在必要的时候 Django 会自动大写首字母。

validators:该字段将要运行的一个验证器的列表。例如 RegexValidator、EmailValidator。

4模型的元数据Meta

除了抽象模型,在模型中定义的字段都会成为表中的列。若是咱们须要给模型指定其余一些信息,例如排序方式、数据库表名等,就须要用到 Meta。Meta 是一个可选的类,具体用法以下:

class Author(models.Model):
    name = models.CharField(max_length=40)
    email = models.EmailField()

    class Meta:
        managed = True
        db_table = 'author'

不知你是否对上述代码有影响。经过 Django 将数据库表反向生成模型时,Django 会默认带上 managed 和 db_table 信息。

我主要说下 Meta 一些重要的属性,其余属性你能够经过文档信息进行学习。

abstract: 若是 abstract = True,模型会指定为抽象模型。它至关于面向对象编程中的抽象基类。

proxy:若是设置了proxy = True,表示使用代理模式的模型继承方式。

db_table:指定当前模型在数据库的表名。

managed:该属性默认值为 True,表示能建立模型和操做数据库表。

ordering:指定该模型生成的全部对象的排序方式。默认按升序排列,若是在字段名前加上字符 “-” 则表示按降序排列,若是使用字符问号 “?” 表示随机排列。

ordering = ['pub_date']             # 表示按'pub_date'字段进行升序排列
ordering = ['-pub_date']            # 表示按'pub_date'字段进行降序排列
ordering = ['-pub_date', 'author']  # 表示先按'pub_date'字段进行降序排列,再按`author`字段进行升序排列。

verbose_name:给模型设置别名。若是不指定它,Django 会使用小写的模型名做为默认值。

verbose_name = "book"
verbose_name = "图书"

verbose_name_plural:由于英语单词有单数和复数两种形式,这个属性是模型对象的复数名。中文则跟 verbose_name 值一致。若是不指定该选项,那么默认的复数名字是 verbose_name 加上 ‘s’ 。

verbose_name_plural = "books"
verbose_name_plural = "图书"

indexes:为当前模型创建索引列表。用法以下:

from django.db import models

class Customer(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    class Meta:
        indexes = [
            models.Index(fields=['last_name', 'first_name']),
            models.Index(fields=['first_name'], name='first_name_idx'),
        ]

5模型的继承

根据模型的 Meta 信息设置,模型继承方式能够分为三种:

5.1抽象模型

模型的 Meta 类中含有 abstract = True 属性。抽象模型通常被看成基类,它持有子类共有的字段。值得注意的是,抽象模型在数据库中不会生成表。

from django.db import models

# 抽象模型
class Person(models.Model):
    name = models.CharField(max_length=500)
    age = models.PositiveIntegerField()
    
    class Meta:
        abstract = True

# 子模型
class Student(Person):
    school_name = models.CharField(max_length=20)

子模型若是没有定义 Meta 类,那么会继承抽象模型的 Meta 类。可是 abstract 属性不会被继承。

5.2多表继承

这种方式继承方式,子模型的父模型能够一个或者多个。

当父类模型是正常的模型,即不是抽象模型,在数据库中有对应表。

虽然在 Model 层不推荐使用多重继承,但 Django 的 ORM 仍是支持这样的使用方式。若是使用多表继承,子模型跟每一个父模型都会添加一个一对一的关系。

from django.db import models

# 父模型 one
class Model_One(models.Model):
    attr1 = models.CharField(max_length=10)

# 父模型 two
class Model_Two(models.Model):
    attr2 = models.CharField(max_length=10)

# 子模型
class Multiple(Model_One, Model_Two):
    attr3 = models.CharField(max_length=10)

多重继承的时候,子类的 ORM 映射会选择第一个父类做为主键管理,其余的父类做为通常的外键管理。

5.3代理模型

使用多表继承时,父类的每一个子类都会建立一张新数据表。可是咱们只是想扩展一些方法,而不想改变模型的数据存储结构。咱们能够将在 Meta 类中增长约束proxy=True 来实现。此时子模型称为父模型代理类,子类中只能增长方法,而不能增长属性。

from django.db import models
from django.contrib.auth.models import User

class Person(User):
    name = models.CharField(max_length=10)
    
    class Meta:
        proxy = True

    def do_something(self):
        pass

class Man(Person):
    job = models.CharField(max_length=20)

class Woman(Person):
    makeup = models.CharField(max_length=20)
相关文章
相关标签/搜索