django的使用2-模型

[TOC]

模型

模型准确且唯一的描述了数据。它包含您储存的数据的重要字段和行为。一般来说,每一个模型都映射一张数据库表。有如下几个点:

  • 每个模型都是一个 Python 的类,这些类继承 django.db.models.Model
  • 模型类的每个属性都相当于一个数据库的字段。
  • 利用这些,Django 提供了一个自动生成访问数据库的 API;

example

定义了一个 Person 模型,拥有 first_name 和 last_name:

1
2
3
4
5
from django.db import models

class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)

first_name 和 last_name 是模型的 字段。每个字段都被指定为一个类属性,并且每个属性映射为一个数据库列。

上面的 Person 模型会创建一个如下的数据库表:

1
2
3
4
5
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);

该表的名称规则 myapp_person = app名称_class名称,可修改。
id 字段会被自动添加,可修改。
创建数据表的语法是根据配置文件setting.py中设置的数据类型来定。

字段类型

模型中每一个字段都应该是某个 Field 类的实例, Django 利用这些字段类来实现以下功能:

  • 字段类型用以指定数据库数据类型(如:INTEGER, VARCHAR, TEXT)。
  • 在渲染表单字段时默认使用的 HTML 视图。
  • 基本的有效性验证功能,用于 Django 后台和自动生成的表单。

Django 内置了数十种字段类型;一起来看看常见的:

  • BooleanField

一个 true/false 字段。

  • CharField

一个字符串字段,适用于小到大的字符串。

  • DateField

一个日期,在 Python 中用一个 datetime.date 实例表示。

  • DateTimeField

一个日期和时间,在 Python 中用一个 datetime.datetime 实例表示。

  • TimeField

一个时间,在 Python 中用 datetime.time 实例表示。

  • DecimalField

一个固定精度的十进制数,在 Python 中用一个 Decimal 实例来表示。

  • EmailField

实际是一个 CharField,使用 EmailValidator 来检查该值是否为有效的电子邮件地址。

  • FloatField

在 Python 中用一个 float 实例表示的浮点数。

  • IntegerField

一个整数。从 -2147483648 到 2147483647 的值在 Django 支持的所有数据库中都是安全的。

  • TextField

一个大的文本字段。该字段的默认表单部件是一个 Textarea。

  • URLField

URL 的 CharField,由 URLValidator 验证。

关系字段

Django 还定义了一组表示关系的字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ForeignKey

from django.db import models

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

class Manufacturer(models.Model):
# ...
pass

字段选项(字段值)

  • null
  • blank
  • choice
  • default
  • primary_key
  • unique
  • unique_for_date
  • unique_for_month
  • unique_for_year

more:https://docs.djangoproject.com/zh-hans/2.2/ref/models/fields/

关联关系

显然,关系型数据库的强大之处在于各表之间的关联关系。 Django 提供了定义三种最常见的数据库关联关系的方法:多对一,多对多,一对一。

多对一关联

定义一个多对一的关联关系,使用 django.db.models.ForeignKey 类。就和其它 Field 字段类型一样,只需要在模型中添加一个值为该类的属性。

例如,如果一个 Car 模型有一个制造者 Manufacturer –就是说一个 Manufacturer 制造许多辆车,但是每辆车都仅有一个制造者– 那么使用下面的方法定义这个关系:

1
2
3
4
5
6
7
8
9
from django.db import models

class Manufacturer(models.Model):
# ...
pass

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

多对多关联

定义一个多对多的关联关系,使用 django.db.models.ManyToManyField 类。就和其他 Field 字段类型一样,只需要在模型中添加一个值为该类的属性。

例如:如果 Pizza 含有多种 Topping (配料) – 也就是一种 Topping 可能存在于多个 Pizza 中,并且每个 Pizza 含有多种 Topping –那么可以这样表示这种关系:

1
2
3
4
5
6
7
8
9
from django.db import models

class Topping(models.Model):
# ...
pass

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

一对一关联

使用 OneToOneField 来定义一对一关系。就像使用其他类型的 Field 一样:在模型属性中包含它。

例如: 位置餐厅 其实可以是一对一的关系。

字段命名限制

  • 一个字段的名称不能是 Python 保留字,因为这会导致 Python 语法错误。
  • 一个字段名称不能包含连续的多个下划线,原因在于 Django 查询语法的工作方式。
  • 字段名不能以下划线结尾,原因同上。

模型属性

模型当中最重要的属性是 Manager。它是 Django 模型和数据库查询操作之间的接口,并且它被用作从数据库当中 获取实例,如果没有指定自定义的 Manager 默认名称是 objects。Manager 只能通过模型类来访问,不能通过模型实例来访问。

模型方法

在模型中添加自定义方法会给的对象提供自定义的“行级”操作能力。与之对应的是类 Manager 的方法意在提供“表级”的操作,模型方法应该在某个对象实例上生效。

重写之前定义的模型方法

还有一个 模型方法的集合,包含了一些可能自定义的数据库行为。尤其是这两个最有可能定制的方法 save() 和 delete()。

1
2
3
4
5
6
7
8
9
10
11
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()

执行自定义 SQL

另一个常见的模式是在模型方法和模块方法中编写自定义 SQL 语句。例如

1
Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')

模型继承

模型继承在 Django 中与普通类继承在 Python 中的工作方式几乎完全相同

Django 有三种可用的集成风格。

  • 常见情况下,仅将父类用于子类公共信息的载体,因为不会想在每个子类中把这些代码都敲一遍。这样的父类永远都不会单独使用,所以 抽象基类 是需要的。
  • 若继承了一个模型(可能来源其它应用),且想要每个模型都有对应的数据表,客官这边请 多表继承。
  • 最后,若只想修改模型的 Python 级行为,而不是以任何形式修改模型字段, 代理模型 会是的菜。

抽象基类

抽象基类在你要将公共信息放入很多模型时会很有用。编写你的基类,并在 Meta 类中填入 abstract=True。该模型将不会创建任何数据表。当其用作其它模型类的基类时,它的字段会自动添加至子类。

一个例子:

1
2
3
4
5
6
7
8
9
10
11
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 模型拥有3个字段: nameagehome_groupCommonInfo 模型不能用作普通的 Django 模型,因为它是一个抽象基类。它不会生成数据表,也没有管理器,也不能被实例化和保存。

多表继承

Django 支持的第二种模型继承方式是层次结构中的每个模型都是一个单独的模型。每个模型都指向分离的数据表,且可被独立查询和创建。继承关系介绍了子类和父类之间的连接。比如:

1
2
3
4
5
6
7
8
9
10
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)

代理模型

使用 多表继承 时,每个子类模型都会创建一张新表。这一般是期望的行为,因为子类需要一个地方存储基类中不存在的额外数据字段。不过,有时候你只想修改模型的 Python 级行为——可能是修改默认管理器,或添加一个方法。

代理模型就像普通模型一样申明。你需要告诉 Django 这是一个代理模型,通过将 Meta 类的 proxy 属性设置为 True。

例如,假设你想为 Person 模型添加一个方法。你可以这么做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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

多重继承

和 Python 中的继承一样,Django 模型也能继承自多个父类模型。请记住,Python 的命名规则这里也有效。第一个出现的基类(比如 Meta )就是会被使用的那个;举个例子,如果存在多个父类包含 Meta,只有第一个会被使用,其它的都会被忽略。

1
2
3
4
5
6
7
8
9
10
class Article(models.Model):
article_id = models.AutoField(primary_key=True)
...

class Book(models.Model):
book_id = models.AutoField(primary_key=True)
...

class BookReview(Book, Article):
pass

参考: