模型

模型是您的数据唯一而且准确的信息来源。它包含您正在储存的数据的重要字段和行为。一般来说,每一个模型都映射一个数据库表。

基础:

  • 每个模型都是一个 Python 的类,这些类继承 django.db.models.Model
  • 模型类的每个属性都相当于一个数据库的字段。每个属性映射为一个数据库列。
  • 综上诉说,Django 给你一个自动生成访问数据库的 API

默认情况下表名是appname_classname,由app名和你创建的模型名组成,可以自定义。

默认情况下会在表中自动创建一个'id'字段,它是默认主键字段,可以自己手动设置

一旦你定义了你的模型,你需要告诉Django你准备*使用*这些模型。你需要修改设置文件中的INSTALLED_APPS,在这个设置中添加包含你 models.py文件的模块的名字。

字段

模型中的每个字段都应该是相应Field类的实例 。Django使用字段类类型来确定一些事情:

  • 字段类型用以指定数据库数据类型(如:INTEGERVARCHARTEXT
  • 默认的HTML表单输入框</ ref / forms / widgets>(如:<input type =“text”> <select>)
  • 用于Django admin和自动生成表单的基本验证。

每个字段都采用一组特定于字段的参数。例如, CharField(及其子类)需要一个max_length参数,该 参数指定VARCHAR用于存储数据的数据库字段的大小。还有一些通用参数:

null如果True,Django将NULL在数据库中存储空值。默认是False

blank如果True,该字段允许为空。默认是False

请注意,这不同于null。 null纯粹与数据库相关,而 blank与验证相关。如果字段有blank=True,则表单验证将允许输入空值。如果字段有blank=False,则需要该字段。

choices

2元组的可迭代(例如,列表或元组),用作此字段的选项。如果给出了这个,则默认表单小部件将是一个选择框而不是标准文本字段,并将限制对给定选项的选择。

选项列表如下所示:

YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)

每个元组中的第一个元素是将存储在数据库中的值。第二个元素由字段的窗体小部件显示。

给定模型实例,choices可以使用该get_FOO_display() 方法访问字段的显示值。

default字段的默认值。这可以是值或可调用对象。如果可调用,则每次创建新对象时都会调用它。help_text使用表单小部件显示额外的“帮助”文本。即使您的字段未在表单上使用,它也对文档很有用。

primary_key如果True,此字段是模型的主键。

如果没有primary_key=True为模型中的任何字段指定,Django将自动添加一个 IntegerField来保存主键,因此primary_key=True除非要覆盖默认的主键行为,否则不需要设置 任何字段。主键字段是只读的。如果更改现有对象上主键的值然后保存它,则将创建一个与旧对象并排的新对象。

unique如果True,该字段在整个表格中必须是唯一的。

自动主键字段

默认情况下,Django为每个模型提供以下字段:

id = models.AutoField(primary_key=True)

这是一个自动递增的主键。

如果您要指定自定义主键,只需primary_key=True在其中一个字段中指定即可 。如果Django看到你明确设置Field.primary_key,它将不会添加自动 id列。

每个模型只需要一个字段primary_key=True(显式声明或自动添加)。

详细字段名

除了和 之外ForeignKey, 每个字段类型都采用可选的第一个位置参数 - 一个详细的名称。如果没有给出详细名称,Django将使用字段的属性名称自动创建它,将下划线转换为空格。ManyToManyFieldOneToOneField

在此示例中,详细名称为:"person's first name"

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

在此示例中,详细名称为:"first name"

first_name = models.CharField(max_length=30)

ForeignKey, ManyToManyField并 OneToOneField要求第一个参数是一个模型类,所以使用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",
)

关系

显然,关系数据库的力量在于将表相互关联。Django提供了定义三种最常见数据库关系类型的方法:多对一,多对多和一对一。

要定义多对一关系,请使用django.db.models.ForeignKey。您可以像使用任何其他Field类型一样使用它:将其包含为模型的类属性。

ForeignKey 需要一个位置参数:与模型相关的类。

from django.db import models

class Manufacturer(models.Model):
# ...
pass class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
# ...

多对多关系

要定义多对多关系,请使用 ManyToManyField。您可以像使用任何其他Field类型一样使用它 :将其包含为模型的类属性。

ManyToManyField 需要一个位置参数:与模型相关的类。

例如,如果a Pizza有多个Topping对象 - 也就是说,a Topping可以在多个比萨饼上,每个Pizza都有多个浇头 - 这就是你如何表示:

from django.db import models

class Topping(models.Model):
# ...
pass class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)

建议(但不要求)a的名称 ManyToManyFieldtoppings在上面的示例中)是描述相关模型对象集的复数。

哪种型号有什么关系并不重要 ManyToManyField,但您应该只将其放在其中一种型号中 - 而不是两种型号。

通常,ManyToManyField实例应该放在要在表单上编辑的对象中。在上面的例子中, toppingsPizza(而不是Topping拥有pizzas ManyToManyField),因为考虑披萨的配料比在多个披萨上打顶更自然。在上面设置的方式,Pizza表单将允许用户选择浇头。

多对多关系中的额外字段

当您只处理简单的多对多关系时,例如混合和匹配比萨饼和浇头,ManyToManyField您只需要一个标准 。但是,有时您可能需要将数据与两个模型之间的关系相关联。

例如,考虑应用程序跟踪音乐家所属的音乐组的情况。一个人与他们所属的团体之间存在多对多的关系,因此您可以使用a ManyToManyField来表示这种关系。但是,您可能希望收集的成员资格有很多详细信息,例如此人加入该组的日期。

对于这些情况,Django允许您指定将用于管理多对多关系的模型。然后,您可以在中间模型上添加额外的字段。中间模型与ManyToManyField使用 through参数指向将充当中介的模型相关联 。对于我们的音乐家示例,代码看起来像这样:

from django.db import models

class Person(models.Model):
name = models.CharField(max_length=128) def __str__(self):
return self.name class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership') def __str__(self):
return self.name class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)

设置中间模型时,您明确指定多对多关系中涉及的模型的外键。此显式声明定义了两个模型的关联方式。

一对一的关系

要定义一对一的关系,请使用 OneToOneField。您可以像使用任何其他Field类型一样使用它 :将其包含为模型的类属性。

当对象以某种方式“扩展”另一个对象时,这对于对象的主键最有用。

OneToOneField 需要一个位置参数:与模型相关的类。

例如,如果您正在构建“地点”数据库,您将在数据库中构建非常标准的内容,例如地址,电话号码等。然后,如果你想在这些地方建立一个餐馆数据库,而不是重复自己并在Restaurant模型中复制这些字段,你可以做Restaurant一个OneToOneFieldto Place(因为一个餐馆“是一个”地方;事实上,处理这通常使用 继承,它涉及隐式的一对一关系)。

OneToOneField字段也接受可选 parent_link参数。

OneToOneField用于自动成为模型主键的类。这不再是真的(尽管你可以手动传入primary_key参数)。因此,现在可以OneToOneField在单个模型上具有多个类型的字段 。

注意:

由于Django的查询查找语法的工作方式,字段名称不能在一行中包含多个下划线。例如:

class Example(models.Model):
foo__bar = models.IntegerField() # 'foo__bar' has two underscores!

Meta选项

使用内部提供模型元数据,如下所示:class Meta

from django.db import models

class Ox(models.Model):
horn_length = models.IntegerField() class Meta:
ordering = ["horn_length"]
verbose_name_plural = "oxen"

模型元数据是“任何不是字段的东西”,例如排序选项(ordering),数据库表名(db_table)或人类可读的单数和复数名称(verbose_name和 verbose_name_plural)。不是必要,添加到模型是完全可选的。

模型属性

objects模型最重要的属性是 Manager。它是为Django模型提供数据库查询操作的接口,用于 从数据库中检索实例。如果Manager未定义自定义,则默认名称为 objects

模型方法

在模型上定义自定义方法,以向对象添加自定义“行级”功能。虽然Manager方法旨在执行“表格范围”的事情,但模型方法应该作用于特定的模型实例。

__str__()

Python“魔术方法”,返回任何对象的字符串表示形式。这是Python和Django在模型实例需要被强制并显示为纯字符串时将使用的内容。最值得注意的是,当您在交互式控制台或管理员中显示对象时会发生这种情况。

你总是想要定义这个方法; 默认情况下根本没有用。

get_absolute_url()

这告诉Django如何计算对象的URL。Django在其管理界面中使用它,并且只要它需要找出对象的URL。

具有唯一标识它的URL的任何对象都应定义此方法。

覆盖预定义的模型方法

还有另一组模型方法,它们封装了一些您想要自定义的数据库行为。特别是你经常想改变方式save()和 delete()工作方式。

您可以自由地覆盖这些方法(以及任何其他模型方法)来改变行为。

用于覆盖内置方法的经典用例是,如果您希望在保存对象时发生某些事情。例如(参见 save()它接受的参数的文档):

from django.db import models

class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField() def save(self, *args, **kwargs):
do_something()
super().save(*args, **kwargs) # Call the "real" save() method.
do_something_else()

重要的是要记住调用超类方法 - 那就是业务 - 以确保对象仍然保存到数据库中。如果您忘记调用超类方法,则不会发生默认行为,也不会触及数据库。super().save(*args, **kwargs)

传递可以传递给模型方法的参数也很重要 - 这就是位的作用。Django将不时扩展内置模型方法的功能,增加新的参数。如果在方法定义中使用,则可以保证代码在添加时自动支持这些参数。*args,**kwargs*args, **kwargs

继承模型

模型继承在Django中与普通类继承在Python中的工作方式几乎完全相同,但也仍有遵循本页开头的内容。这意味着其基类应该继承自django.db.models.Model

您必须做出的唯一决定是,您是希望父模型本身是模型(使用自己的数据库表),还是父母只是通过子模型可见的公共信息的持有者。

Django中有三种可能的继承方式。

  1. 通常,您只想使用父类来保存您不希望为每个子模型键入的信息。这个类不会被孤立使用,所以抽象基类就是你所追求的。
  2. 如果你是现有模型的子类(可能是完全来自另一个应用程序的东西),并希望每个模型都有自己的数据库表,那么 多表继承是最佳选择。
  3. 最后,如果您只想修改模型的Python级行为,而不以任何方式更改模型字段,则可以使用 代理模型。

抽象基类

当您想要将一些公共信息放入许多其他模型时,抽象基类非常有用。你写你的基类,并把abstract=True在元 类。然后,此模型将不用于创建任何数据库表。相反,当它用作其他模型的基类时,其字段将添加到子类的字段中。

一个例子:

from django.db import models

class CommonInfo(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField() class Meta:
abstract = True class Student(CommonInfo):
home_group = models.CharField(max_length=5)

Student模型将有三个领域:nameage和 home_group。该CommonInfo模型不能用作普通的Django模型,因为它是一个抽象基类。它不生成数据库表或具有管理器,并且无法直接实例化或保存。

从抽象基类继承的字段可以使用其他字段或值覆盖,也可以使用删除None

对于许多用途,这种类型的模型继承将完全符合您的要求。它提供了一种在Python级别分解公共信息的方法,同时仍然只在数据库级别为每个子模型创建一个数据库表。

Meta继承

当创建抽象基类时,Django使 您在基类中声明的任何Meta内部类可用作属性。如果子类没有声明自己的Meta 类,它将继承父类的Meta。如果孩子想要扩展父类的Meta类,它可以将其子类化。例如:

from django.db import models

class CommonInfo(models.Model):
# ...
class Meta:
abstract = True
ordering = ['name'] class Student(CommonInfo):
# ...
class Meta(CommonInfo.Meta):
db_table = 'student_info'

Django确实对抽象基类的Meta类进行了一次调整:在安装Meta属性之前,它设置了abstract=False。这意味着抽象基类的子节点本身不会自动成为抽象类。当然,您可以创建一个继承自另一个抽象基类的抽象基类。您只需要记住abstract=True每次都明确设置。

多表继承

Django支持的第二种模型继承是当层次结构中的每个模型都是模型本身时。每个模型对应于自己的数据库表,可以单独查询和创建。继承关系引入子模型与其每个父模型之间的链接(通过自动创建OneToOneField)。例如:

from django.db import models

class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80) class Restaurant(Place):
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)

尽管数据将驻留在不同的数据库表PlaceRestaurant,但所有字段都将可用。所以这些都是可能的:

>>> Place.objects.filter(name="Bob's Cafe")
>>> Restaurant.objects.filter(name="Bob's Cafe")

Meta和多表继承

在多表继承情况下,子类从其父类的Meta类继承是没有意义的。所有的Meta选项都已经应用于父类,并且再次应用它们通常只会导致矛盾的行为(这与基类本身不存在的抽象基类情况形成对比)。

因此,子模型无法访问其父级的Meta类。但是,有一些有限的情况,子进程从父进程继承行为:如果子进程没有指定 ordering属性或 get_latest_by属性,它将从其父进程继承它们。

如果父级有一个排序而你不希望孩子有任何自然顺序,你可以明确地禁用它:

class ChildModel(ParentModel):
# ...
class Meta:
# Remove parent's ordering effect
ordering = []

继承和反向关系

因为多表继承使用隐式 OneToOneField链接子项和父项,所以可以从父项向下移动到子项,如上例所示。但是,这会占用名称和 关系的默认related_name值 。如果要将这些类型的关系放在父模型的子类上,则 必须 在每个此类字段上指定该属性。

class Supplier(Place):
customers = models.ManyToManyField(Place)

这会导致错误,添加related_name到该customers字段将解决错误:models.ManyToManyField(Place,related_name='provider')

代理模型

使用多表继承时,会为模型的每个子类创建一个新的数据库表。这通常是所需的行为,因为子类需要一个位置来存储基类上不存在的任何其他数据字段。但是,有时您只想更改模型的Python行为 - 可能更改默认管理器或添加新方法。

这就是代理模型继承的用途:为原始模型创建代理。您可以创建,删除和更新代理模型的实例,并且将保存所有数据,就像使用原始(非代理)模型一样。不同之处在于您可以更改代理中的默认模型排序或默认管理器等内容,而无需更改原始内容。

代理模型声明为普通模型。你通过设置类的proxy属性告诉Django它是一个代理模型。MetaTrue

例如,假设您要向Person模型添加方法。你可以这样做:

from django.db import models

class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30) class MyPerson(Person):
class Meta:
proxy = True def do_something(self):
# ...
pass

MyPerson班在同一个数据库表作为它的父工作 Person类。特别是,任何新的实例Person也可以通过MyPerson,反之亦然:

>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

你仍然可以使用一个代理模型来定义模型的默认排序方法你也许不会想一直对“Persion”进行排序,但是通常情况下用代理模型根据“姓氏”属性进行排序这很简单。:

class OrderedPerson(Person):
class Meta:
ordering = ["last_name"]
proxy = True

现在,正常Person查询将是无序的,OrderedPerson查询将按顺序排序last_name

代理继承和非托管模型之间的差异¶

代理模型继承可能看起来与使用managed模型Meta类的属性创建非托管模型非常相似。

通过仔细设置,Meta.db_table您可以创建一个非托管模型,该模型可以隐藏现有模型并为其添加Python方法。但是,如果您进行任何更改,则需要保持两个副本同步,这将是非常重复和脆弱的。

另一方面,代理模型的行为与它们所代表的模型完全相同。它们始终与父模型同步,因为它们直接继承其字段和管理器。

一般规则是:

  1. 如果要镜像现有模型或数据库表,并且不想要所有原始数据库表列,请使用Meta.managed=False。该选项通常用于建模不受Django控制的数据库视图和表。
  2. 如果您想要更改模型的仅Python行为,但保留与原始字段相同的字段,请使用Meta.proxy=True。这进行了设置,以便在保存数据时代理模型是原始模型的存储结构的精确副本。

Django文档阅读之模型的更多相关文章

  1. Django文档阅读-Day1

    Django文档阅读-Day1 Django at a glance Design your model from djano.db import models #数据库操作API位置 class R ...

  2. Django文档阅读-Day2

    Django文档阅读 - Day2 Writing your first Django app, part 1 You can tell Django is installed and which v ...

  3. Django文档阅读-Day3

    Django文档阅读-Day3 Writing your first Django app, part 3 Overview A view is a "type" of Web p ...

  4. 吴裕雄--天生自然PythonDjangoWeb企业开发:Django文档阅读简介

    Django是基于MVC模式的框架,虽然也被称为“MTV”的模式,但是大同小异.对我们来说,需要了解的是无论是MVC模式还是MTV模式,甚至是其他的什么模式,都是为了解耦.把一个软件系统划分为一层一层 ...

  5. Django文档阅读之执行原始SQL查询

    Django提供了两种执行原始SQL查询的方法:可以使用Manager.raw()来执行原始查询并返回模型实例,或者可以完全避免模型层直接执行自定义SQL. 每次编写原始SQL时都要关注防止SQL注入 ...

  6. Django文档阅读之聚合

    聚合 我们将引用以下模型.这些模型用来记录多个网上书店的库存. from django.db import models class Author(models.Model): name = mode ...

  7. Django文档阅读之查询

    创建对象 为了在Python对象中表示数据库表数据,Django使用直观的系统:模型类表示数据库表,该类的实例表示数据库表中的特定记录. 要创建对象,请使用模型类的关键字参数对其进行实例化,然后调用s ...

  8. css文档之盒模型阅读笔记

    前段时间抽空仔细阅读了w3c的css文档关于盒模型方面的一些基础知识.边读边记录了一些要点,在此做些整理,与大家分享,如有理解有误之处,请不吝指教. 1.综述 文档中的每个元素被描绘为矩形盒子.渲染引 ...

  9. Keras 文档阅读笔记(不定期更新)

    目录 Keras 文档阅读笔记(不定期更新) 模型 Sequential 模型方法 Model 类(函数式 API) 方法 层 关于 Keras 网络层 核心层 卷积层 池化层 循环层 融合层 高级激 ...

随机推荐

  1. LINUX部署JAVA项目

    Tomcat 应用服务器搭建好 安装 tomcat 所需依赖或工具软件 sudo yum -y update sudo yum -y install wget java unzip 使用 wget 下 ...

  2. 六.深浅copy

    先问问大家,什么是拷贝?拷贝是音译的词,其实他是从copy这个英文单词音译过来的,那什么是copy? copy其实就是复制一份,也就是所谓的抄一份.深浅copy其实就是完全复制一份,和部分复制一份的意 ...

  3. [Ignatius and the Princess III] 整数的无序拆分(DP + 生成函数)

    整数的有序拆分就是隔板法,无序拆分则有两种处理方法 DP递推 我们假设P(n,m)P(n,m)P(n,m)是正整数nnn无序拆分为mmm个正整数的方案数 对于某一种拆分,不妨将拆分出来的mmm个数从小 ...

  4. B/S之大文件分段上传、断点续传

    4GB以上超大文件上传和断点续传服务器的实现 随着视频网站和大数据应用的普及,特别是高清视频和4K视频应用的到来,超大文件上传已经成为了日常的基础应用需求. 但是在很多情况下,平台运营方并没有大文件上 ...

  5. 如何把上传图片时候的文件对象转换为图片的url !

    getObjectURL(file) { var url = null; if (window.createObjectURL != undefined) { url = window.createO ...

  6. 3-STM32物联网开发WIFI(ESP8266)+GPRS(Air202)系统方案升级篇(HTTP介绍,TCP实现HTTP下载文件)

    https://www.cnblogs.com/yangfengwu/p/10357564.html 看了好多文章.....唉,还是自己亲自动手用网络监控软件测试吧 先看这个节安装WEB服务器.... ...

  7. 【洛谷】P1443 马的遍历

    题目:https://www.luogu.org/problemnew/show/P1443 简单的BFS模板题——因为我写出来了. 分析过程: n*m矩阵,用二维数组 数据不大,二维数组稳了 先把二 ...

  8. MATLAB 可以画的各种类型的图总结

    MATLAB® 提供了各种可用来绘制数据图的函数.下表对常见的图形函数进行了分类和说明. 线图 数据分布图 离散数据图 极坐标图 等高线图 向量场 plot area stairs polarplot ...

  9. Tcl二进制数据

    binary format 格式化描述符 参数1 参数2...参数N binary scan 二进制数据 格式化描述符 变量1 变量2 ... 变量N 格式化描述符由两部分组成,第一是格式化类型关键字 ...

  10. 蚂蚁Pincap头条

    去年(18年)年底想出来看看机会,最后很幸运地拿到了 PingCAP,今日头条的 offer 以及蚂蚁金服的口头 offer.想着可以总结一下经验,分享一下自己这一段”骑驴找马”过的心路历程.当然,一 ...