七、Django的orm之多表操作(一)
多表操作
三种关系:一对一,一对多,多对多
一、数据准备,创建表模型
-
配置settings,连接到数据库
# settings更改配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'orm03',
'HOST':'127.0.0.1',
'PORT':3306,
'USER':'root',
'PASSWORD':'123'
}
}# 项目中的init写入: import pymysql pymysql.install_as_MySQLdb()
-
在应用中的models.py创建模型
from django.db import models# 比较常用的信息放到这个表里面 class Author(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() authorDetail=models.OneToOneField( to="AuthorDetail", to_field="nid", on_delete=models.CASCADE # on_delete=models.SET_NULL()设置不级连删除,对方删除后,自己设置为空 ) # 与AuthorDetail建立一对一的关系(OneToOneField),一对一的这个关系字段写在两个表的任意一个表里面都可以 # 就是foreignkey+unique,只不过不需要我们自己来写参数了,并且orm会自动帮你给这个字段名字拼上一个_id,数据库中字段名称为authorDetail_id # 不常用的放到这个表里面 class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday=models.DateField() # telephone=models.BigIntegerField() 不方便以后查询,需要再转str查,不如直接用str类型 telephone=models.CharField(max_length=30) addr=models.CharField(max_length=64) # 与Author建立一对一的关系(OneToOneField这个关系字段写在两个表的任意一个表里面都可以) class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() # 相当于CharField,后期可多一层校验规则,判断是否是xx.@...这样的邮箱地址 # 多对多的表关系,在mysql的时候建立这种关系,需要手动创建一个第三张表,然后写上两个字段,每个字段外键关联到另外两张多对多关系的表;orm的manytomany自动帮我们创建第三张表,两种方式建立关系都可以,以后的学习我们暂时用orm自动创建的第三张表,因为手动创建的第三张表我们进行orm操作的时候,很多关于多对多关系的表之间的orm语句方法无法使用 #如果你想删除某张表,你只需要将这个表注销掉,然后执行那两个数据库同步指令就可以了,自动就删除了。 # 与Publish建立一对多的关系 # 与Author建立多对多的关系 class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) publish=models.ForeignKey( to="Publish", to_field="nid", on_delete=models.CASCADE ) # 与Publish建立一对多的关系,外键字段建立在多的一方,字段publish如果是外键字段,那么它自动是int类型 #foreignkey里面可以加很多的参数,to指向表,to_field指向你关联的字段,不写这个,默认会自动关联主键字段,on_delete级联删除 #字段名称不需要写成publish_id,orm在翻译foreignkey的时候会自动给你这个字段拼上一个_id,这个字段名称在数据库里面就自动变成了publish_id # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表,并且注意一点,你查看book表的时候,你看不到这个字段,因为这个字段就是创建第三张表的意思,不是创建字段的意思,所以只能说这个book类里面有authors这个字段属性 authors=models.ManyToManyField(to='Author') # 注意不管是一对多还是多对多,写to这个参数的时候,最后后面的值是个字符串,不然你就需要将你要关联的那个表放到这个表的上面
总结:
创建表:一对一:# OneToOneField xx = models.OneToOneField( to='表名', to_field='字段名', on_delete=models.CASCADE ) # to_field可以不写,默认是关联到另一张表的主键 # on_delete在1.x版本的django中不用写,默认是级联删除的,2.x版本的django要写 # on_delete=models.SET_NULL()设置不级连删除,对方删除后,自己设置为空 一对多:# ForeignKey xx = models.ForeignKey( to='表名', to_field='字段名', on_delete=models.CASCADE ) 多对多:# ManyToManyField xx = models.ManyToManyField(to='另外一个表名') #这是自动创建第三表 # 还可以手动创建第三张表,(用在还有其他一些自己的字段的时候,暂时忽略) # class BookToAuthor(models.Model): # book_id = models.ForeignKey(to='Book') # author_id = models.ForeignKey(to='Author') # xx = models.CharField(max_length=12) 注意:不管是一对多还是多对多,写to这个参数的时候,最后后面的值是个字符串,不然你就需要将你要关联的那个表放到这个表的上面
-
执行数据库同步指令:
python manage.py makemigrations
python manage.py migrate
结果如下:
二、关系表添加记录
拓展一种添加数据的方式,是django内部提供的一个后台管理系统
-
创建一个超级用户:
python manage.py createsuperuserUsername (leave blank to use 'administrator'): yangzm Email address: Password: 94211314ming.
-
访问127.0.0.1:8000/admin/,使用刚注册好的用户名、密码,登录后台管理系统
-
在应用app01下的admin.py注册我们要用的表
from django.contrib import admin
from app01 import models # 导入models# Register your models here. admin.site.register(models.Author) # admin.site.register方法注册 admin.site.register(models.Publish) admin.site.register(models.Book) admin.site.register(models.AuthorDetail)
-
重新运行项目,就会发现表已经在后台的管理系统当中了
-
点击里面的添加按钮,根据要求,就可以添加数据了
-
增
-
一对一表的增加
一对一关联的表是:Author表的authorDetail字段关联的 AuthorDetail表的nid字段
def query(request):new_author_detail = models.AuthorDetail.objects.create( birthday='1996-02-14', telephone='188753698755', addr='天界大陆' ) # 方式1: models.Author.objects.create( name='liangdao', age='26', authorDetail=new_author_detail # 直接等于对象 ) new_author_obj = models.AuthorDetail.objects.create( birthday='1886-02-14', telephone='18615724935', addr='幽暗密林' ) # 方式2:(常用) models.Author.objects.create( name='baobao', age='55', authorDetail_id=new_author_obj.nid # 把对象的id属性关联起来 )
-
一对多的增加
一对多关联的表是:Book表的publish字段关联的 Publish表的nid字段
# 方式1:
models.Book.objects.create(
title='回村的诱惑',
publishDate='2018-12-12',
price=88.88,
publish=models.Publish.objects.get(nid=1)
)
# 方式2:(常用)
models.Book.objects.create(
title='回村的诱惑2',
publishDate='2000-11-11',
price=45,
publish_id=models.Publish.objects.get(nid=1).nid
) -
多对多的增加
多对多关联的表是:Book表的authors字段关联的 Author表的nid字段
# 方式1:常用
book_obj = models.Book.objects.get(nid=1)
book_obj.authors.add([1,2])
# 方式2:
author1 = models.Author.objects.get(nid=1)
author2 = models.Author.objects.get(nid=3)
book_obj = models.Book.objects.get(nid=2)
book_obj.authors.add([author1, author2])
- 删
一对一和一对多的删除和单表删除是一样的
-
一对一的删
# Author表一对一关联AuthorDetail表
models.AuthorDetail.objects.get(nid=2).delete()
# 当AuthorDetail表删除数据时,会影响到Author表,因为级联删除
models.Author.objects.get(nid=4).delete()
# 当Author表删除数据时,不会影响到AuthorDetail表
注意:- 表一关联表二,做了级联,表二删除,表一跟着删除
- 表一关联表二,没做级联,表二删除,表一报错
- 表一关联表二,无论做没做级联,表一删除数据,都不会影响到表二
-
一对多的删
# Book表一对多关联Publish表
models.Publish.objects.get(nid=2).delete()
# Publish表删除数据,影响到Book表
models.Book.objects.get(nid=7).delete()
# Book表删除数据,不会影响到Publish表 -
多对多关系的删除
实际上就是去删除多对多自动生成的表中的关系的记录
# Book表多对多的关联Author表
book_obj = models.Book.objects.get(nid=3)
book_obj.authors.remove(3)
# 先找到book里id是3的书,然后通过authors属性删除作者id是3的数据book_obj = models.Book.objects.get(nid=3) book_obj.authors.remove(*[2,3]) # 先找到book里id是3的书,然后通过authors属性删除作者id是2和3的数据 book_obj = models.Book.objects.get(nid=3) book_obj.authors.clear() # 先找到book里id是3的书,然后通过authors属性找到关系表,删除所有id是3的书数据 book_obj = models.Book.objects.get(nid=3) book_obj.authors.clear() book_obj.authors.add(*[1,]) # 先删除所有id是3的书数据,然后给id是3的书加入一个id是1的作者 book_obj = models.Book.objects.get(nid=3) book_obj.authors.set('1') # 同样完成上述需求,先清空再添加(set必须给个参数,否则报错) book_obj = models.Book.objects.get(nid=3) book_obj.authors.set(['5','6']) # 删除然后更新,添加多个
注意:
- Book表删除数据,会影响到关系表的数据
- Author表删除数据,也同样会影响到关系表的数据
- 更新
-
一对一
models.Author.objects.filter(nid=6).update(
name='baoge',
age='16',
authorDetail=models.AuthorDetail.objects.get(nid=5)
# authorDetail_id = 4 两种方式
) -
一对多
models.Book.objects.filter(pk=6).update(
title='回娘家的诱惑',
price=188,
publish=models.Publish.objects.get(pk=2)models.Publish.objects.filter(pk=2).update( id=4, # 没有级联更新,报错!! ) # 注:默认级联删除,级联更新没有默认
-
多对多
# 就是setbook_obj = models.Book.objects.get(nid=3) book_obj.authors.set('1') # 同样完成上述需求,先清空再添加(set必须给个参数,否则报错) book_obj = models.Book.objects.get(nid=3) book_obj.authors.set(['5','6']) # 删除然后更新,添加多个