模型
模型准确且唯一的描述了数据,每一个模型映射一张数据库表,包含了数据的表名、字段、每行数据, (1)每个模型是一个py类,继承 django.db.models.Model (2)类属性,映射数据库表字段
1、快速上手定义模型
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
上面 person 模型创建如下数据库表,创建一张数据库表,表名:app名_person,字段是 id、first_name、last_name,并且对字段做了限制,其中id是自动创建的主键,
creat table myapp_persion (
'id' seial NOT NULL PRIMARY KEY,
'first_name' varchar(30) NOT NUL,
'last_name' varchar(30) NOT NULL
);
2、使用模型
你在自己的app中定义了这个模型,要使用它, (1)需要将app注册到 django 框架中,在settings文件 install_app 字段列表内添加app (2)使用manage.py工具生成 数据库迁移文件,这个文件用于在数据库创建表格:py manage.py makemigrations (3)使用manage.py工具将生成的迁移文件转换成数据库表:py manage.py migrate
3、字段
字段在类属性中定义,帝国一字段时应小心避免与模型api的名称冲突,如clean、save、delete
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
4、字段类型
模型中每一个字段都是某个 Field 类的实例,django利用这些字段类实现以下功能:字段类型用以指定数据库数据类型,
- django 内置了数十种字段类型,常见的字段类型:
- autofield:主键,一般不需要设置
- charfield:存储字符串,必须指定长度
- intergerfild:存在整型
- booleanfield:存在布尔型
- foreignkey:1对多
- datatimefield:存储时间日期
- manytomanyfield:多对多
from django.db import models
class Project(models.Model):
PROJECT_TYPE_CHOICE = (
(1, "web"),
(2, "App"),
(3, "微服务"),
)
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200, verbose_name="测试项目名称")
version = models.CharField(max_length=20, verbose_name="版本")
type = models.IntegerField(verbose_name="产品类型", choices=PROJECT_TYPE_CHOICE)
description = models.CharField(max_length=200, verbose_name="项目描述", blank=True, null=True)
status = models.BooleanField(default=True, verbose_name="状态")
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="创建人", db_column="created_by")
created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
updated_at = models.DateTimeField(auto_now=True, verbose_name="最近更新时间")
members = models.ManyToManyField(User, related_name="project_members",
through="ProjectMember",
through_fields=('project', 'user'))
5、字段参数
每种字段都需要指定一些特定的参数,如charfield需要指定 max_length 的值,用以指定数据库存 varchar 数据时用的字节数,一些可选的参数是通用的,如:
- blank:设置为 null,表示字段输入允许为空,默认false
- null:设置为 true,当字段输入为空时,django在数据库中将字段设置为NULL
- choices:对用户而言该字段是可供选择的下拉框,并将限制下拉框的值,用法如上代码。每个二元组的第一个值会储存在数据库中,而第二个值将只会用于在表单中显示。
- default:是个单选框,单选框默认是选择的,如:status = models.BooleanField(default=True, verbose_name=“状态”),
- help_text:是个文本提示,在界面上跟控件一起展示
- primary_key:设置为 true,则将该字段设置该模型的主键,如:id = models.AutoField(primary_key=True),模型中如果没有设置 primary_key,
则django自动添加一个 integerfield 字段并设为主键。 - unique:设置为 true,这个字段的值必须在整个表保持唯一
其他通用字段,参考:https://docs.djangoproject.com/zh-hans/4.0/ref/models/fields/#common-model-field-options
6、自动设置主键
默认情况下,django给每个模型一个自动递增的主键,这个主键类型在应用的apps.py中的 AppConfig.default_auto_field 中指定,在老版本中,这个字段类型是 autofield,新版本如下:
from django.apps import AppConfig
class PollsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
7、字段备注名
除了字段foreignkey、 mangtomangfield、onetoonefield,其他字段类型都接受可选参数 verbose_name,如果不指定该值,django默认将字段的属性名,作为该参数值展示在网页上,并把属性名的下划线转换为空格,field类第一个参数为 verbose_name,所以可以省略参数名字,如下:
from django.db import models
first_name = models.CharField("个人名字", max_length=30)
first_name = models.CharField(max_length=30)
foreignkey、 mangtomangfield、onetoonefield 因为接收的第一个参数为类名,所以可以在后面添加 verbose_name 参数,如:
from django.db import models
class Project(models.Model):
name = models.CharField("测试项目名称", max_length=200)
version = models.CharField("版本", max_length=20, verbose_name="版本")
description = models.CharField("项目描述", max_length=200, blank=True, null=True)
class ProjectEnv(models.Model):
project = models.ForeignKey(Project, on_delete=models.PROTECT, verbose_name="测试项目")
8、关联关系
django提供了定义三种最常见的数据库关联关系:多对一,多对多,一对一
多对一关联
多对一关系使用 django.db.models.ForeignKey类,需要添加一个位置参数,值为要关联的模型类名。建议设置 foreignkey 的字段名一般为 关联的模型名。 场景如下:界面展示为一个下拉框,下拉框关联出 所有我们创建的用户。 我们在管理后台创建了4个用户。我们输入测试项目的信息_创建人时候,会有一个下拉框,关联出我们在用户界面创建的用户
from django.contrib.auth.models import User
from django.db import models
class Project(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, verbose_name="创建人", db_column="created_by")
class ProjectMember(models.Model):
project = models.ForeignKey(Project, on_delete=models.PROTECT, verbose_name="测试项目")
project1 = models.ForeignKey(Project, on_delete=models.CASCADE, verbose_name="测试项目")
更多例子:https://docs.djangoproject.com/zh-hans/4.0/topics/db/examples/many_to_one/
多对多关联
(1)使用 django.db.models.ManyToManyField 类,就和其他 Field 字段类型一样,只需要在你模型中添加一个值为该类的属性。一个披萨中有多个配料,一个配料存在多个披萨中, 对于多对多的模型,可以在任何一个模型中添加manytomanyfield字段,不能同时设置2个,一般情况下,需要将 manytomangfield放到披萨中,因为需要在披萨中编辑它的配料。 如果是测试平台的话,那就是1个项目中可以包含多个成员,1个成员也可以存在多个项目中。为了实现这种多对多的使用功能,我们使用manytomany处理 如下处理:
from django.db import models
class Topping(models.Model):
pass
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
(2)多对多中添加额外的属性字段啊 Django 允许你指定用于控制多对多关系的模型。你可以在中间模型当中添加额外的字段。 在实例化 ManyToManyField 的时候使用 through 参数指定多对多关系使用哪个中间模型, Django 会自动生成一个表来管理多对多关系。但是,如果你想手动指定中间表,你可以使用 through 选项来指定代表你要使用的中间表的 Django 模型。
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)
一对一关联
from django.db import models
class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
def __str__(self):
return "%s the place" % self.name
class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False)
def __str__(self):
return "%s the restaurant" % self.place.name
class Waiter(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
def __str__(self):
return "%s the waiter at %s" % (self.name, self.restaurant)
9、跨文件模型
关联另一个应用中的模型也是可以的,在定义模型的文件开头导入需要被关联的模型。接着就可以在其他有需要的模型类当中关联它了。比如:
from django.db import models
from geography.models import ZipCode
class Restaurant(models.Model):
zip_code = models.ForeignKey(ZipCode, on_delete=models.SET_NULL, blank=True, null=True,)
10、字段命名限制
- 模型的字段名不能是py的关键字
- 字段名不能包含双下划线
- 字段名不能以下划线开头、结尾
- sql关键字是可以应用在字段名中
11、meta类
使用内部 meta类 来给模型赋予元数据,模型的元数据就是“所有非字段的内容”,比如:排序、数据库表名、界面名称,这些都不是必须得,在meta类中可选 以下是meta类的可选参数:https://docs.djangoproject.com/zh-hans/4.0/ref/models/options/
from django.db import models
class Base(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
m2m = models.ManyToManyField(OtherModel,
related_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)ss",
)
class Meta:
verbose_name = "pizza"
verbose_name_plural = "stories"
index_together = ["pub_date", "deadline"]
unique_together = [['driver', 'restaurant']]
proxy = True
permissions = [('can_deliver_pizzas', 'Can deliver pizzas')]
get_latest_by = ['-priority', 'order_date']
db_tablespace = "tables"
indexes = [models.Index(fields=['shortcut'], db_tablespace='other_indexes')]
db_table = 'music_album'
abstract = True
ordering = ["horn_length"]
class Student(Base):
home_group = models.CharField(max_length=5)
class Question(models.Model):
text = models.TextField()
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
class Meta:
order_with_respect_to = 'question'
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'),
]
class Customer1(models.Model):
age = models.IntegerField()
class Meta:
constraints = [models.CheckConstraint(check=models.Q(age__gte=18), name='age_gte_18'),]
meta类的其他可选参数:
- default_manager_name
- default_related_name
- managed
- order_with_respect_to
- default_permissions
- required_db_features
12、模型属性
objects是 manager的默认名称,manager是django模型和数据库查询操作之间的捷库,并且它被应用于从数据库获取实例。
13、模型方法
__str__() __eq__() __hash__() get_absolute_url() 其他额外的实例方法 我们经常会复写的方法:__str__()、get_absolute_url()
14、模型继承
(1)抽象基类:仅将父类用于子类公共信息的载体,因为你不会想在每个子类中把这些代码都敲一遍
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)
(2)多表继承:若你继承了一个模型(可能来源其它应用),且想要每个模型都有对应的数据表,客官这边请 多表继承。
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)
(3)代理模型:只想修改模型的 Python 级行为,而不是以任何形式修改模型字段
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
15、如何 管理模型
如果你有很多的models.py文件,如下处理: 创建一个 models 包。删除 models.py,创建一个 myapp/models 目录,包含一个 init.py 文件和存储模型的文件。你必须在 init.py 文件中导入这些模块,比如,若你在 models 目录下有 organic.py 和 synthetic.py:
from .organic import Person
from .synthetic import Robot
|