文章目录
一.模型迁移与反向迁移
1.Model --> DB (模型 to 数据库)
(1)迁移步骤
生成迁移文件 python manage.py makemigrations
执行迁移文件 python manage.py migrate
(2)迁移文件的生成
根据models文件生成对应的迁移文件
根据models和已有迁移文件差别 生成新的迁移文件
(3)迁移原理 了解
先去迁移记录查找,哪些文件未迁移过
app_label + 迁移文件名字
执行未迁移的文件
执行完毕,记录执行过的迁移文件
(4)可以指定迁移的app
python manage.py makemigrations app(注意app的名字后面不允许加/)
python manage.py migrate
(5)注意:
对已经迁移过的模型添加字段时没有给默认值,再次迁移会报错:
django所有被迁移的字段,都是not null 的约束,不允许为null
添加新的字段的时候,必须指定默认值。
(6)重新迁移
删除迁移文件
migrations所涉及的迁移文件
删除迁移文件产生的表
删除迁移记录
django-migrations
2.DB --> Model (数据库 to 模型)
DB -> Model
反向生成到指定得app下 --》 python manager.py inspectdb > App/models.py
元信息中包含一个属性 managed=False 不支持迁移
如果自己的模型不想被迁移系统管理,也可以使用 managed=False进行声明
创建一个动物表:
输入:python manager.py inspectdb > App/models.py
在从服务器下载下来:
你就会发现有了animal表,不好的地方就是会把那13张默认的表也导下来。。。
如果在元信息中添加了managed = False,那么就代表该模型不受迁移管理
二.模型关系
1.一对一
(1)应用场景
用于复杂表的拆分
扩展新功能
OneToOneField
确认主从关系,谁声明关系谁就是从表
底层实现,使用外键实现的,对外键添加了唯一约束
创建一对一模型:
class Student(models.Model):
name = models.CharField(max_length=32)
class Meta:
db_table = 'student'
class IdCard(models.Model):
cardnum = models.IntegerField()
i_student = models.OneToOneField(Student)
class Meta:
db_table = 'idcard'
idcard的DDL展示:
(2)添加
1.添加主表数据
创建根路由:
url(r'^one/',include('OneToOneApp.urls'))
创建子路由:
url(r'^addStudent/',views.addStudent),
生成视图函数:
def addStudent(request):
student = Student()
student.name = '源'
student.save()
return HttpResponse('添加成功')
运行结果:
2.添加从表数据
创建子路由:
url(r'^addIdcard/',views.addIdcard),
生成视图函数:
按照添加主表数据的操作,我们可以试着写下添加从表数据:
def addIdcard(request):
idcard = IdCard()
idcard.cardnum = '110'
idcard.save()
return HttpResponse('添加成功')
运行结果:
通过结果,我们会发现会报错。实际上,在默认情况下,django所有的字段都是not null的,非空的,如果想设置字段为nulll,那么可以添加索引:
class IdCard(models.Model):
cardnum = models.IntegerField()
i_student = models.OneToOneField(Student,null=True,blank=True)
class Meta:
db_table = 'idcard'
执行迁移,再运行:
添加从表数据,注意外键的null值
修改了模型之后,null和blank都必须要迁移,否则不能生效
3.绑定
创建子路由:
url(r'^bind/',views.bind),
生成视图函数:
def bind(request):
student = Student.objects.last()
idcard = IdCard.objects.last()
# 针对于模型
idcard.i_student = student
# 针对于表
# idcard.i_student_id = student.id 也可以
idcard.save()
return HttpResponse('绑定成功')
运行结果:
思考:
以现在的数据基础上 一个student 一个idcard
(1)以现在的数据基础上,再次添加student对象,然后进行绑定,可不可以?(可以)
(2)以现在的数据基础上,再次添加idcard对象,然后进行绑定,可不可以?(不可以)
(3)删除
1.删除从表数据
创建子路由:
url(r'^deleteIdcard',views.deleteIdcard)
生成视图函数:
def deleteIdcard(request):
idcard = IdCard.objects.last()
idcard.delete()
return HttpResponse('删除从表成功')
运行结果:
2.删除主表数据
(1)删除主表数据,默认的情况是什么???
创建子路由:
url(r'^deleteDefault/',views.deleteDefault)
生成视图函数:
def deleteDefault(request):
s = Student.objects.last()
s.delete()
return HttpResponse('删除主表数据,默认的情况是什么')
运行结果:
默认情况下,OneToOneField中有一个属性叫做on_delete,该值如果没有,那么默认就是CASCADE,这个代表的是级联,删除主表数据,从表对应的数据将删除
class IdCard(models.Model):
cardnum = models.IntegerField()
i_student = models.OneToOneField(Student,on_delete=models.CASCADE)
class Meta:
db_table = 'idcard'
(2)删除主表数据,然后对应的从表数据的外键设置为null
class IdCard(models.Model):
cardnum = models.IntegerField()
#在设置on_delete=models.SET_NULL的时候,必须在之前指定该字段必须为null
i_student = models.OneToOneField(Student,null=True,blank=True,on_delete=models.SET_NULL)
class Meta:
db_table = 'idcard'
新添数据:
创建子路由:
url(r'^deleteNull/',views.deleteNull),
生成视图函数:
def deleteNull(request):
s = Student.objects.last()
s.delete()
return HttpResponse('删除主表数据,从表设置为null')
运行结果:
(3)删除主表数据,然后对应的从表数据的外键设置默认值
class IdCard(models.Model):
cardnum = models.IntegerField()
i_student = models.OneToOneField(Student,null=True,blank=True,on_delete=models.SET(5))
class Meta:
db_table = 'idcard'
添加数据:
创建子路由:
url(r'^deleteSet/',views.deleteSet),
生成视图函数:
def deleteSet(request):
s = Student.objects.first()
s.delete()
return HttpResponse('删除主表数据,从表数据设置默认值')
运行结果:
(4)删除主表数据,然后对应的从表有关联数据则不可以删除
class IdCard(models.Model):
cardnum = models.IntegerField()
#如果主表下有对应的从表数据,那么就不允许删除,没有对应的数据,才可以删除
i_student = models.OneToOneField(Student, null=True, blank=True, on_delete=models.PROTECT)
class Meta:
db_table = 'idcard'
创建子路由:
url(r'^deleteProtect/',views.deleteProtect),
生成视图函数:
def deleteProtect(request):
s = Student.objects.last()
s.delete()
return HttpResponse('有关联数据,则不允许删除')
运行结果:
如果将i_student_id设置为null:
models.PROTECT:使从表数据受保护的
当存在级联数据的时候,删除主表数据,会抛出异常
主表不存在级联数据的时候,可以删除
开发中为了防止误操作,我们通常会设置为此模式
(4)查询
1.根据从表的对象查询主表的数据
创建子路由:
url(r'^getStudent/',views.getStudent),
生成视图函数:
def getStudent(request):
idcard = IdCard.objects.last()
# i_student是idcard的显性属性,显性函数就是可以直接看到的属性
print(idcard.i_student.name)
return HttpResponse('根据从表对象来查询主表对象')
运行结果:
2.根据主表的对象,来查询从表的数据
创建子路由:
url(r'^getIdcard/',views.getIdcard),
生成视图函数:
def getIdcard(request):
student = Student.objects.last()
# 当主表对象查询从表数据的时候可以使用隐性属性
# 隐性属性:看不到 但是可以使用
# 1v1: student.idcard
# 1vm: stdent.idcard_set
print(student.idcard.cardnum)
return HttpResponse('根据主表对象来查询从表数据')
运行结果:
2.一对多
(1)创建模型
创建一对多模型,并进行迁移
class Dept(models.Model):
name = models.CharField(max_length=32)
class Meta:
db_table = 'dept'
class Emp(models.Model):
name = models.CharField(max_length=32)
e_dept = models.ForeignKey(Dept)
class Meta:
db_table = 'emp'
(2)添加
创建主路由:
url(r'^onetomany/',include('OneToMany.urls')),
1.添加主表数据
创建子路由:
url(r'^addDept/',views.addDept),
生成视图函数:
def addDept(request):
dept = Dept()
dept.name = 'python开发部'
dept.save()
return HttpResponse('添加主表成功')
运行结果:
2.添加从表数据
创建子路由:
url(r'^addEmp/',views.addEmp),
生成视图函数:
def addEmp(request):
emp = Emp()
emp.name = '张三'
emp.save()
return HttpResponse('添加从表成功')
运行结果:
由上可知:一对多的外键也不能为null
重新修改模型:
class Emp(models.Model):
name = models.CharField(max_length=32)
e_dept = models.ForeignKey(Dept,null=True,blank=True)
class Meta:
db_table = 'emp'
再次运行:
(3)绑定
创建子路由:
url(r'^bind/',views.bind),
生成视图函数:
def bind(request):
dept = Dept.objects.last()
emp = Emp.objects.last()
emp.e_dept = dept
emp.save()
return HttpResponse('绑定成功')
运行结果:
思考:
(1) 以现在已有数据的基础之上,如果在主表中添加一个数据,然后绑定,可以不可以?
在主表中添加一个数据:
再进行绑定,运行结果:
以现在已有数据的基础之上,如果在主表中添加一个数据,然后绑定 -->可以
(2) 以现在已有数据的基础之上,如果在从表中添加一个数据,然后绑定,可以不可以?
在从表中添加一个数据:
再进行绑定,运行结果:
以现在已有数据的基础之上,如果在从表中添加一个数据,然后绑定 -->可以
(4)删除
1.删除从表数据
创建子路由:
url(r'^deleteEmp/',views.deleteEmp),
生成视图函数:
def deleteEmp(request):
emp = Emp.objects.last()
emp.delete()
return HttpResponse('删除从表成功')
运行结果:
2.删除主表数据
(1)默认情况下,是级联删除CASCADE
创建子路由:
url(r'^deleteDefault/',views.deleteDefault),
生成视图函数:
def deleteDefault(request):
dept = Dept.objects.last()
dept.delete()
return HttpResponse('默认删除主表')
运行结果:
(2)删除主表,从表设置为null
重新修改模型:
class Emp(models.Model):
name = models.CharField(max_length=32)
e_dept = models.ForeignKey(Dept, null=True, blank=True, on_delete=models.SET_NULL)
class Meta:
db_table = 'emp'
添加数据:
创建子路由:
url(r'^deleteNull/',views.deleteNull),
生成视图函数:
def deleteNull(request):
dept = Dept.objects.last()
dept.delete()
return HttpResponse('删除主表,从表数据设置为null')
运行结果:
(3)删除主表,如果有关联从表数据,就报错,不允许删除
重新修改模型:
class Emp(models.Model):
name = models.CharField(max_length=32)
e_dept = models.ForeignKey(Dept, null=True, blank=True, on_delete=models.PROTECT)
class Meta:
db_table = 'emp'
添加数据:
创建子路由:
url(r'^deleteProtect/',views.deleteProtect),
生成视图函数:
def deleteProtect(request):
dept = Dept.objects.last()
dept.delete()
return HttpResponse('删除主表,有从表的对应数据,则报错')
运行结果:
删除:数据删除同一对一模型一样
删除主表数据:默认级联从表数据
修改on_delete属性为models.PROTECT
有级联数据数据 抛异常
没有级联数据 可以正常删除
修改on_delete=models.SET_NULL
有级联数据 外键值设置为null
没有级联数据 直接删除
删除字表数据 不管字表返回得是列表还是单个数据 都可以直接删除 应用场景 多选删除
(5)查询
1.根据从表对象查询主表数据
创建子路由:
url(r'^getDept/',views.getDept),
生成视图函数:
def getDept(request):
emp = Emp.objects.get(pk=3)
print(emp.e_dept.name)
return HttpResponse('根据从表的数据查询主表的数据')
运行结果:
2.根据主表对象查询从表数据
创建子路由:
url(r'^getEmps/',views.getEmps),
生成视图函数:
def getEmps(request):
dept = Dept.objects.last()
emps = dept.emp_set.all()
for e in emps:
print(e.id,e.name)
return HttpResponse('根据主表对象查询从表的数据')
运行结果:
查询:级联对象获取
从获取主
显性属性
主获取从
隐性属性
默认是 模型小写_set
该属性得返回值类型是relatedManager类型
注意relatedManager是一个不可以迭代得对象 所以需要调用Manager得方法
relatedManager也是Manager的一个子类
relatedManager对象可以调用filter、exclude、all、切片
3.多对多
(1)创建模型
创建多对多模型,并进行迁移:
class Custom(models.Model):
name = models.CharField(max_length=32)
class Meta:
db_table = 'custom'
class Goods(models.Model):
name = models.CharField(max_length=32)
g_custom = models.ManyToManyField(Custom)
class Meta:
db_table = 'goods'
Django自动生成关系表:
ManyToManyField
产生表的时候会产生单独的关系表
关系表中存储关联表的主键,通过多个外键实现的,多个外键联合唯一
会产生额外的关系表
表中使用多个外键实现
外键对应关系表的主键
(2)添加
创建主路由:
url(r'^manytomany/',include('ManyToManyApp.urls')),
1.添加主表数据
创建子路由:
url(r'^addCustom/',views.addCustom),
生成视图函数:
def addCustom(request):
custom = Custom()
custom.name = '张三'
custom.save()
return HttpResponse('添加主表数据')
运行结果:
2.添加从表数据
创建子路由:
url(r'^addGoods/',views.addGoods),
生成视图函数:
def addGoods(request):
goods = Goods()
goods.name = '手办'
goods.save()
return HttpResponse('添加从表数据')
运行结果:
3.添加关系表数据
创建子路由:
url(r'^addRelation/',views.addRelation),
生成视图函数:
方式一:
def addRelation(request):
custom = Custom.objects.last()
goods = Goods.objects.last()
#从表的显性属性,来添加关系表的数据
goods.g_custom.add(custom)
return HttpResponse('添加关系表数据')
方式二:
def addRelation(request):
custom = Custom.objects.last()
goods = Goods.objects.last()
# 主表的隐性属性,来添加关系表的数据
custom.goods_set.add(goods)
return HttpResponse('添加关系表数据')
运行结果:
需要注意的是:关系表中外键的联合唯一
(3)删除
1.删除主表数据
创建子路由:
url(r'^deleteCustom/',views.deleteCustom),
生成视图函数:
def deleteCustom(request):
custom = Custom.objects.last()
custom.delete()
return HttpResponse('删除custom是不是级联删除???')
运行结果:
删除主表数据,默认是级联删除
2.删除从表数据
数据展示:
创建子路由:
url(r'^deleteGoods/',views.deleteGoods),
生成视图函数:
def deleteGoods(request):
goods = Goods.objects.first()
goods.delete()
return HttpResponse('删除goods是不是级联删除???')
运行结果:
删除从表数据,也是级联删除
3.删除关系表数据
数据展示:
创建子路由:
url(r'^deleteRelation/',views.deleteRelation),
生成视图函数:
方式一:
def deleteRelation(request):
custom = Custom.objects.first()
goods = Goods.objects.first()
# 根据从表的显性属性 删除
goods.g_custom.remove(custom)
return HttpResponse('删除关系表数据')
方式二:
def deleteRelation(request):
custom = Custom.objects.first()
goods = Goods.objects.first()
# 根据主表的隐性属性 删除
custom.goods_set.remove(goods)
return HttpResponse('删除关系表数据')
运行结果:
(4)查询
1.根据从表数据查询主表数据
创建子路由:
url(r'^getCustom/',views.getCustom),
生成视图函数:
def getCustom(request):
goods = Goods.objects.first()
customs = goods.g_custom.all()
for custom in customs:
print(custom.id,custom.name)
return HttpResponse('根据从表的数据查询主表的数据')
运行结果:
2.根据主表数据查询从表数据
创建子路由:
url(r'^getGoods/',views.getGoods),
生成视图函数:
def getGoods(request):
custom = Custom.objects.first()
goods_list = custom.goods_set.all()
for goods in goods_list:
print(goods.id,goods.name)
return HttpResponse('根据主表的数据查询从表的数据')
运行结果: