模型(Model)设计-为模型提供初始化的数据
文章目录
目标
前面已经介绍了如何快速入门,现在开始熟练掌握一些知识
- 掌握不同方式下,为模型提供初始化的数据
- 掌握给单表、关系表提供初始化的数据
回顾
a、模型(Model)示例
回顾一下之前练习时,设计的模型类。
# 使用的model
from django.db import models
# Create your models here.
class Grade(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=8, verbose_name="年级名称", unique=True)
class Meta:
db_table = 't_grade'
def __str__(self):
# 默认显示类的name字段
return self.name
@classmethod
def create(cls, _name):
if _name is 'admin':
obj = cls(name=_name)
return obj
else:
print('不合法')
class Teacher(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=10, verbose_name="教师名称")
# class_id = models.ManyToManyField(to='Class', db_column="class_id", db_table="t_teach2cls")
class Meta:
db_table = 't_teacher' # 定义表名为t_teacher
def __str__(self):
# 默认显示类的name字段
return self.name
class Class(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=16, verbose_name="编辑名称", unique=True)
grade_id = models.ForeignKey(to='Grade', to_field='id', on_delete=models.CASCADE, db_column="grade_id")
teacher_id = models.ManyToManyField(to='Teacher', db_column="teacher_id", db_table="t_teach2cls")
class Meta:
db_table = 't_class'
def __str__(self):
# 默认显示类的name字段
return self.name
class Student(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=16, verbose_name="学生名称")
GENDER_CHOICES = (
(0, u"女"),
(1, u"男"),
)
gender = models.CharField(max_length=4, verbose_name="性别", choices=GENDER_CHOICES)
class_id = models.ForeignKey(to='Class', to_field='id', on_delete=models.CASCADE, db_column="class_id")
course_id = models.ManyToManyField(to='Course', through='Score', through_fields=('student_id', 'course_id'),
db_column="course_id")
class Meta:
db_table = 't_student'
def __str__(self):
# 默认显示类的name字段
return self.name
class Course(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=16, verbose_name="课程名称", unique=True)
teacher_id = models.ForeignKey(to='Teacher', to_field='id', on_delete=models.CASCADE, db_column="teacher_id")
class Meta:
db_table = 't_course'
def __str__(self):
# 默认显示类的name字段
return self.name
class Score(models.Model):
id = models.AutoField(primary_key=True)
student_id = models.ForeignKey(verbose_name='学生', to="Student", to_field='id', on_delete=models.CASCADE,
db_column="student_id")
course_id = models.ForeignKey(verbose_name='课程', to="Course", to_field='id', on_delete=models.CASCADE,
db_column="course_id")
score = models.IntegerField(verbose_name="分数", default=0)
class Meta:
db_table = 't_score'
unique_together = [('student_id', 'course_id'), ]
def __str__(self):
v = self.student_id.name + "---" + self.course_id.name
return v
资料
一、为模型提供初始化的数据
第一次配置应用时,用硬编码的数据预备数据库有时很很有用。你能通过迁移和固定内容提供初始数据。
1.1、通过固定内容提供初始数据
你也能通过固定内容提供数据,不过,这些数据不会自动加载,除非你使用 TransactionTestCase.fixtures。
固定内容是一个 Django 知道如何导入数据库的集合。若你已有一些可用数据,最直接的创建固定内容的方式是使用manage.py dumpdata 命令。或者,你可以手写固定内容;固定数据能被写作 JSON,XML 或 YAML (要求已安装 PyYAML)文档。 序列化文档 拥有更多这些支持的 序列化格式 的细节信息。
下面我以JSON文件来演示具体操作步骤
第一步:在对应应用下创建一个文件夹fixtures
如下图所示
补充说明:
- Django 从哪里寻找固定内容文件 默认情况下:Django 在每个应用的 fixtures 目录中查找固定内容,故需要在对应应用下创建这个目录。你可以将配置项 FIXTURE_DIRS 设为一个 Django 需要额外寻找的目录列表。
第二步:创建对应JSON文件
如下图所示
第三步:编写对应JSON文件
编写对应JSON文件,需要更加模型类的关系,存在几种情况
a、模型(Model)为单表关系的JSON文件
回顾中单表模型,Grade、 Teacher对应的JSON文件如下
[{
"model": "app_b.Grade",
"pk": 1,
"fields": {
"name": "一年级"
}
}, {
"model": "app_b.Grade",
"pk": 2,
"fields": {
"name": "二年级"
}
}, {
"model": "app_b.Grade",
"pk": 3,
"fields": {
"name": "三年级"
}
}, {
"model": "app_b.Grade",
"pk": 4,
"fields": {
"name": "四年级"
}
}, {
"model": "app_b.Grade",
"pk": 5,
"fields": {
"name": "五年级"
}
}, {
"model": "app_b.Grade",
"pk": 6,
"fields": {
"name": "六年级"
}
}]
[{
"model": "app_b.Teacher",
"pk": 1,
"fields": {
"name": "张三"
}
}, {
"model": "app_b.Teacher",
"pk": 2,
"fields": {
"name": "李四"
}
}, {
"model": "app_b.Teacher",
"pk": 3,
"fields": {
"name": "王五"
}
}]
代码说明:
- model:对应模型,一般是应用名称.模型类名称,比如 “app_b.Teacher” ,“app_b.Grade”。
- pk:表示主键。
- fields:代表模型类中的字段。
a、模型(Model)为一对多关系的JSON文件
回顾中一对多模型Course, 他有外键 models.ForeignKey
。对应的JSON文件如下
[{
"model": "app_b.Course",
"pk": 1,
"fields": {
"name": "生物",
"teacher_id": 1
}
}, {
"model": "app_b.Course",
"pk": 2,
"fields": {
"name": "体育",
"teacher_id": 1
}
}, {
"model": "app_b.Course",
"pk": 3,
"fields": {
"name": "物理",
"teacher_id": 2
}
}]
代码说明:
- teacher_id: 这里外键直接用对应表的主键值,比如我这里就是整型
a、模型(Model)为多对多关系的JSON文件
回顾中多对多模型 Class、Student ,他们有多对多字段 models.ManyToManyField
。对应的JSON文件如下两种情况
- 情况一、多对多没有定义新的模型类,比如Class
[{
"model": "app_b.Class",
"pk": 1,
"fields": {
"name": "一年一班",
"grade_id": 1,
"teacher_id": [1, 2]
}
}, {
"model": "app_b.Class",
"pk": 2,
"fields": {
"name": "一年二班",
"grade_id": 1,
"teacher_id": [1, 3]
}
}, {
"model": "app_b.Class",
"pk": 3,
"fields": {
"name": "二年一班",
"grade_id": 2
}
}, {
"model": "app_b.Class",
"pk": 4,
"fields": {
"name": "二年二班",
"grade_id": 2
}
}, {
"model": "app_b.Class",
"pk": 5,
"fields": {
"name": "三年一班",
"grade_id": 3
}
}, {
"model": "app_b.Class",
"pk": 6,
"fields": {
"name": "三年二班",
"grade_id": 3
}
}]
代码说明:
-
teacher_id: 在对应模型类Class中 ,
teacher_id = models.ManyToManyField(to='Teacher', db_column="teacher_id", db_table="t_teach2cls")
如此定义,没有针对多对多关系,定义新的模型类,故在提供数据的时候,该字段已列表方式赋值。比如"teacher_id": [1, 2]
。 -
情况二、多对多有定义新的模型类,比如 Student,将多对多映射到新的模型类 Score
[{
"model": "app_b.Score",
"pk": 1,
"fields": {
"student_id": 1,
"course_id": 1,
"score": 60
}
}, {
"model": "app_b.Score",
"pk": 2,
"fields": {
"student_id": 1,
"course_id": 2,
"score": 59
}
}, {
"model": "app_b.Score",
"pk": 3,
"fields": {
"student_id": 1,
"course_id": 3,
"score": 59
}
}, {
"model": "app_b.Score",
"pk": 4,
"fields": {
"student_id": 2,
"course_id": 1,
"score": 77
}
}, {
"model": "app_b.Score",
"pk": 5,
"fields": {
"student_id": 2,
"course_id": 2,
"score": 99
}
}, {
"model": "app_b.Score",
"pk": 6,
"fields": {
"student_id": 2,
"course_id": 3,
"score": 80
}
}]
- model: 由于在模型类 Student 中,
course_id = models.ManyToManyField(to='Course', through='Score', through_fields=('student_id', 'course_id'), db_column="course_id")
如此定义,有针对多对多的关系,定义新的模型类Score,故在提供数据的时候,按照模型类Score赋值就行。
第四步:导入对应JSON文件
加载数据非常简单:只需调用 manage.py loaddata , 是你刚创建的固定内容的文件名。每次你运行 loaddata,数据都会从固定内容读出,重新装入数据库。这意味着若你修改了某个固定内容创建的行,随后再次运行 loaddata ,你会丢掉所有的修改。
(LearnDjango) D:\Programma\Python\Python3\LearnDjango\DjangoProjectA>python manage.py loaddata grade.json
Installed 6 object(s) from 1 fixture(s)
导入后效果:
1.2、通过SQL语句提供初始数据
为提供初始化的SQL数据django提供了传递数据库任意的SQL的钩子,这些SQL是当你运行syncdb的时候在CREATE TABLE后会被运行的。你可以使用这个钩子去填充默认记录,或者创建SQL函数或者视图函数,触发器等等。
钩子是很简单的:django会在你的app目录下寻找一个名叫 sql/<modelname>.sql 的文件,这个文件的中的modelname是你的模型名字的小写。所以,如果你有一个名叫Person的模型在你的名为myapp的app目录下,你可以在你的myapp目录下的sql/person.sql文件里面添加任意的SQL,下面是一个例子:
INSERT INTO myapp_person (first_name, last_name) VALUES ('John', 'Lennon');
INSERT INTO myapp_person (first_name, last_name) VALUES ('Paul', 'McCartney');
每个sql文件(如果有的话),应该包含有效的往表中插入数据的语句(分号隔开的insert语句)。sql文件可以被manage.py中的sqlcustom,sqlreset,sqlall和reset命令读取。注意的是,如果你有多个sql文件,他们被运行的顺序是无法保证的,你唯一能做的是,保证需要用的的数据表都是事先已经被创建好的
下面是一个例子:值得注意的是,这个初始化仅在第一次运行syncdb时创建
特定数据库后端的sql数据django提供了特定后端的sql数据的钩子。特定后端的sql会被先运行(后端和ENGINE的值一样才起效)。
举个例子,如果你的app包含sql/person.sql和sql/person.sqlite3.sql两个文件,并且数据库使用sqlite,django会先运行sql/person.sqlite3.sql,然后才运行sql/person.sql。相信这个例子很容易理解,django会先寻找文件<appname>/sql/<modelname>.<backend>.sql文件,<appname>是你的应用目录,<modelname>是你的模型的名字的小写形式,<backend>是你的数据库引擎。