模型迁移原理
迁移过程
定义数据模型,在models.py中定义模型类。
生成迁移文件
python manage.py makemigrations [AppName]
- 如不指定AppName则对整个项目生成迁移文件,指定AppName则只对指定的应用生成迁移文件。
- 迁移文件实质上就是生成数据库SQL语句,存放在AppName下的migrations目录中。
- 迁移文件就是根据models.py中的定义生成。
- 如果models.py中有变化,则会检测并生成新的迁移文件
- 执行迁移
python manage.py migrate
- 执行迁移
- 执行迁移脚本,既将迁移文件在数据库中执行。
- 迁移过程则是先到django_migrations表中查看迁移记录,表中会记录上次迁移的AppName名称和迁移文件名称。
- 执行未迁移的文件。
- 执行完毕后,把执行的记录写入到django_migrations表中。
重新迁移
在某些时候需要重新迁移模型时,一般会有如下步骤
1、删除migrations目录下的迁移文件
2、删除数据库表,再次执行迁移命令。
% python manage.py makemigrationsMigrations for 'Apps':Apps/migrations/0001_initial.py- Create model Idcard- Create model Person% python manage.py migrateOperations to perform:Apply all migrations: Apps, admin, auth, contenttypes, sessionsRunning migrations:No migrations to apply.
这时会发现迁移文件可以正常生成,但执行迁移却并不会更新至数据库。这是因为Django会把上一次迁移记录到数据库的django_migrations表中。只需再执行第三步即可。
3、需要删除表中的这条记录就可以了。
mysql> delete from django_migrations where app='Apps';Query OK, 1 row affected (0.00 sec)
再次执行迁移命令即可。
模型关系
一对一 OneToOneField
应用场景
- 用于复杂表的拆分,如将用户表和用户身份信息表拆分
- 扩展新功能,如系统运行一段时间,数据量很大,增加新的字段
- 模型创建
class Person(models.Model):
p_name = models.CharField(max_length=32)
p_age = models.IntegerField(default=18)
class Idcard(models.Model):
idcard = models.CharField(max_length=18)
# 建立一对一关系
id_person = models.OneToOneField(Person, null=True, blank=True, on_delete=models.CASCADE
实现原理
- 在外键ForeignKey的基础上增加了唯一约束,就实现了一对一的关系。
- 通过DDL语句可以看到实现原理
create table Apps_idcard
(
id int auto_increment
primary key,
idcard varchar(18) not null,
id_person_id int null,
constraint id_person_id
unique (id_person_id), -- 约束
constraint Apps_idcard_id_person_id_1282a770_fk_Apps_person_id
foreign key (id_person_id) references Apps_person (id) -- 外键
);
一对一模型的主从关系
- 主表:上例种的Person既为主表
- 从表:谁声明关系谁是从表,上例种的IdCard为从表
一对一关系删除时的操作
默认on_delete为models.CASCADE
- 从表数据删除,主表不受影响
- 主表数据删除,从表数据直接删除
models.PROTECT
- 保护模式
- 主表删除数据时,如果存在关联数据,会抛出保护异常。
- 必须先删除主表的级联数据,才可以删除主表数据。
models.SET_NULL
- 设置级联数据为空
- 删除主表时,关联数据设置为空,要求关联数据字段允许为空。
models.SET_DEFAULT
- 存在默认值
models.SET()
- 指定值
一对一模型查询
通过主表查询从表数据
- 隐性属性
- QuerySet.从表字段
通过从表查询主表数据
- 显性属性直接调用
- QuerySet.id_主表
一对多 ForeignKey
- 模型的创建
class ClassName(models.Model):
cname = models.CharField(max_length=18)
def __str__(self):
return self.cname
class Meta:
db_table = 'classname'
class Student(models.Model):
s_name = models.CharField(max_length=18)
# 通过ForeignKey的方式进行一对多关系创建
cname = models.ForeignKey(ClassName, on_delete=models.DO_NOTHING)
def __str__(self):
return self.s_name
class Meta:
db_table = 'student'
实现原理
- 通过创建数据库外键的方式进行一对多关系创建
create table student
(
id int auto_increment
primary key,
s_name varchar(18) not null,
cname_id int not null,
constraint student_cname_id_3f032e9c_fk_classname_id
foreign key (cname_id) references classname (id)
);
一对多模型主从关系
- 主表为ClassName
- 从表为Student
一对多模型的查询操作
通过主查询从表数据
- 主表对象.从表小写_set.过滤器方法
- 同样支持all、filter、get、exclude等方法
def getstudent(request): # 主查从,通过班级查询学生信息 classname = ClassName.objects.get(cname='318') item = classname.student_set.all() print(item) return HttpResponse('get success {}'.format(item))
通过从表查询主表数据
- 从表对象.外键字段.属性
def getclass(request): # 从查主,通过学生信息查询班级 sname = Student.objects.last() classname = sname.cname.cname return HttpResponse('{}'.format(classname))
- 从表对象.外键字段.属性
跨关系查询
- 从表查主表:从表类名.objects.过滤器(外键名小写属性比较符=’*‘)
- 主表查从表:主表类名.objects.过滤器(从表类名小写属性比较符=’*‘)
```python
def vlookup(request):
主表查询从表数据
cname = ClassName.objects.filter(student__s_name=’lisi’)从表查询主表数据
student = Student.objects.filter(cname__cname=’318’)
return HttpResponse(student) ```
