对于表操作,表之间的关联关系,必须理解他们之间的关系,对于编程很重要。可以看看映射关系、外键和relationship查询 ,至少明白外键相关基本知识。
(一)多表查询 一对一:models.OneToOneField(to_field='id',to='Authordatil') 一对多:(外键设置唯一性) models.ForeignKey(to='Publish',to_field='id') 多对多:自动生成第三张表 models.ManyToManyField(to='Author') (二)创建表模型 作者与详情 ( 一对一 ) 书与作者( 多对多 ) 出版社与书(一对多 ) 出版社:id name add email 书: id name price publish 作者: id name sex authordatil 详情: id photo addressmodels.py 文件,创建数据模型
from django.db import models class Publish(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max_length=100) address=models.CharField(max_length=64) email=models.EmailField() def __str__(self): return '%s,%s,%s'%(self.name,self.address,self.email) class Author(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max_length=32) choices=((0,'女'),(1,'男')) sex=models.SmallIntegerField(choices,default=0) #数字整型 #作者与详情:(一对一) to='AuthorDetail' 加引号,这个表能找到就可以,不用引号,类必须在上面定义 authordatil=models.OneToOneField(to_field='id',to='Authordatil',on_delete=models.CASCADE) def __str__(self): return self.name class Authordatil(models.Model): id=models.AutoField(primary_key=True) photo=models.CharField(max_length=124) address=models.CharField(max_length=64) class Book(models.Model): id=models.AutoField(primary_key=True) name=models.CharField(max_length=32) price=models.DecimalField(max_digits=5,decimal_places=2) #出版社与书(一对多关系)外检设置唯一性,关联的表,关联的字段 publish=models.ForeignKey(to='Publish',to_field='id',on_delete=models.CASCADE) #书与作者关系是多对多关系 authors=models.ManyToManyField(to='Author')id 字段是自动添加的
对于外键字段,Django 会在字段名上添加"_id" 来创建数据库中的列名
外键字段 ForeignKey 有一个 null=True 的设置(它允许外键接受空值 NULL),你可以赋给它空值 None 。
直接添加Book,views中定义一个方法,简单测试:
models.Book.objects.create(name='红楼梦', price=20.0, publish_id=1) return HttpResponse('成功插入一条Book记录!')看看控制台,会报错了 'Cannot add or update a child row: a foreign key constraint fails 初步判定主键约束错误,也就是说publish_id 对应的Publish不存在。那就先添加几个Publish吧 views中定义一个方法:
def addPublish(request): models.Publish.objects.create(name='北京出版社', address='北京', email='itjavawfc@163.com') models.Publish.objects.create(name='安徽出版社', address='安徽', email='itjavawfc@163.com') models.Publish.objects.create(name='人教版出版社', address='北京', email='itjavawfc@163.com') li=[] for i in range(5): li.append(models.Publish(name='新华出版社%s' % i, address='北京', email='itjavawfc@163.com')) # 批量生成对象 models.Publish.objects.bulk_create(li) return HttpResponse('成功插入Publish记录!')查看数据库信息: 出版社Publish数据有了,现在继续测试添加Book功能了。
def addBookById(request): models.Book.objects.create(name='红楼梦', price=20.0, publish_id=101) return HttpResponse('成功插入一条Book记录!')查看数据库数据,可以看到数据已经成功插入了。
简单理解刚才的问题:主键约束了之后,插入book前提是已经有了外键的数据,publish_id,也就是有一个Publish记录,这样才可以插入Book记录,且publish_id正好是Publish记录中对应的一条记录。
通过对象添加记录 def addBookByPublish(request): publish = models.Publish.objects.filter(pk=101).first() models.Book.objects.create(name='红楼梦', price=34.5, publish=publish) return HttpResponse('通过对象插入一条记录!')首先得到一个publish对象,然后作为参数直接插入到Book表中,看看数据库信息。
# pk 表示主键,一旦主键改变,还是会找到对应的主键来获取对象,如果通过主键查询道德数据为null,那么表示不存在这个记录,也就无法正常插入Book了。通过queryset对象的update方法修改
通过对象的属性修改,调用对象的save()方法保存
通过queryset对象的update方法修改
方式一:通过 _id 修改 def upDateBook(request): models.Book.objects.filter(pk=4).update(name='西游记', publish_id=102) return HttpResponse('通过ID修改!')修改前数据表Book信息 修改后信息如下 方式二:通过 对象修改修改
def upDateBookByPublish(request): publish = models.Publish.objects.filter(pk=103).first() models.Book.objects.filter(pk=4).update(name='东游记',price=100.0, publish=publish) return HttpResponse('通过对象修改!')数据库当前数据
通过对象的属性修改,调用对象的save()方法保存方式一:通过 _id 修改
def upDateBookByIDBook(request): book = models.Book.objects.filter(pk=4).first() book.publish_id = 104 book.price = 200.0 book.save() return HttpResponse('upDateBookByIDBook!')方式二:通过对象修改
def upDateBookBook(request): book = models.Book.objects.filter(pk=4).first() publish = models.Publish.objects.filter(pk=105).first() book.publish = publish book.save() return HttpResponse('upDateBookBook!')多对多增加记录
多对多删除记录
多对多清空记录
多对多修改记录
多对多增加记录 先准备测试用的数据
(1)通过对象添加记录
def addAuthorDetail(request): models.Authordatil.objects.create(photo='www.baidu.com/author1.png', address='天上人间1包间') models.Authordatil.objects.create(photo='www.baidu.com/author2.png', address='天上人间2包间') models.Authordatil.objects.create(photo='www.baidu.com/author3.png', address='天上人间3包间') models.Authordatil.objects.create(photo='www.baidu.com/author4.png', address='天上人间4包间') return HttpResponse('添加AuthorDetail') def addAuthor(request): models.Author.objects.create(name='tom', sex=0,authordatil_id=1) models.Author.objects.create(name='tony', sex=1,authordatil_id=2) models.Author.objects.create(name='jack', sex=1,authordatil_id=3) models.Author.objects.create(name='ant', sex=0,authordatil_id=4) return HttpResponse('添加addAuthor')之前库中有一本书东游记
现在就要为这边《东游记》这本书添加作者
def addAuthorByBook(request): # 为红楼梦这本书添加一个作者 tom = models.Author.objects.filter(name='tom').first() book = models.Book.objects.filter(name='东游记').first() tony = models.Author.objects.filter(name='tony').first() jack = models.Author.objects.filter(name='jack').first() book.authors.add(tom) # 一次添加两个作者,中间用逗号隔开 book.authors.add(tony, jack) return HttpResponse('给书添加作者')看数据库数据表: bookapp_book_authors (2)通过 id 添加记录
直接上代码
def addAuthorByBookById(request): # 为红楼梦这本书添加一个作者 book = models.Book.objects.filter(name='东游记').first() # 一次添加两个作者,中间用逗号隔开 book.authors.add(4) return HttpResponse('addAuthorByBookById')看看数据库表 也就是说,得到了book之后,直接通过作者的id作为参数,找到了作者,然后直接添加,内部django帮助封装了一层其实。
多对多删除记录 remove() # 可以传对象,可以传id,可以传多个(1)通过对象删除记录
def delBookOfAuthor(request): # 删除东游记作者名字是tom的作者 tom = models.Author.objects.filter(name='tom').first() book = models.Book.objects.filter(name='东游记').first() book.authors.remove(tom) return HttpResponse('delBookOfAuthor')可以看到,bookapp_book_authors表中的tom记录已经删掉了
(2)通过id删除记录
def delBookOfAuthorByID(request): # 删除东游记作者id是3、4的两个作者 book = models.Book.objects.filter(name='东游记').first() book.authors.remove(3,4) return HttpResponse('delBookOfAuthorByID') 多对多清空记录 clear() # 没有参数 # 删除东游记作者id是3、4的两个作者 book = models.Book.objects.filter(name='东游记').first() book.authors.clear() return HttpResponse('delBookOfAllAuthor') 多对多修改记录 set() # 先清空在增加,必须传列表,列表里面可以是对象,可以是id(1)通过对象修改记录
def updateBookAuthor(request): tom = models.Author.objects.filter(name='tom').first() book = models.Book.objects.filter(name='东游记').first() book.authors.set([tom, ]) return HttpResponse('updateBookAuthor')(2)通过id修改记录
def updateBookAuthorID(request): # 修改东游记作者为作者id是3、4的作者 book = models.Book.objects.filter(name='东游记').first() book.authors.set([3,4 ]) return HttpResponse('updateBookAuthorID')正向查询和反向查询
正向查询:关联字段在从表,由从表查询主表中的数据 -----> 按字段查询 反向查询:关联字段在从表,由主表查询从表中的数据 -----> 按表名小写查询1、一对一基于对象的跨表查询
正向:正向查询按 字段 反向:反向查询按 表名小写 def findBookAndPublish(request): # 1.正向 查询东游记这本书的出版社邮箱 book = Book.objects.filter(name='东游记').first() # book.publish 就是出版社对象 pulish = book.publish print(pulish.email) # 2.反向 查询地址是北京的出版社出版的图书 publish = Publish.objects.filter(address='北京').first() # publish.book_set.all() 拿出所有的图书 books = publish.book_set.all() # 统计一下条数 books = publish.book_set.all().count() print(books) return HttpResponse('findBookAndPublish')结果:
itjavawfc@163.com 02、多对多基于对象的跨表查询
正向:正向查询按 字段.all() 反向:反向按 表名小写_set.all()``` ```python def findBookAndPublishMoreToMore(request): # 1.查询红楼梦这本书所有的作者 book = Book.objects.filter(name='东游记').first() book.authors.all() # 是所有的作者,是一个queryset对象,可以继续点 print(book.authors.all()) # 2.查询lqz写的所有书 lqz = Author.objects.filter(name='jack').first() books = lqz.book_set.all() print(books) return HttpResponse('findBookAndPublishMoreToMore') <QuerySet [<Author: jack>, <Author: ant>]> <QuerySet [<Book: Book object (4)>]>1、一对一的基于双下划线的跨表查询
正向:按 字段,跨表可以在filter,也可以在values中 反向:按 表名小写,跨表可以在filter,也可以在values中 def findBookTyp1(request): # 1.查询tom作者的照片 正向查询 跨表的话,按字段 # 以author表作为基表 ret = Author.objects.filter(name='tom').values('authordatil__photo') print(ret) # 2.以authordetail作为基表 反向查询,按表名小写 跨表的话,用表名小写 ret = Authordatil.objects.filter(author__name='tom').values('photo') print(ret) return HttpResponse('findBookTyp1')打印结果:
<QuerySet [{'authordatil__photo': 'www.baidu.com/author1.png'}]> <QuerySet [{'photo': 'www.baidu.com/author1.png'}]>2、多对多的基于双下划线的跨表查询
正向:按 字段,跨表可以在filter,也可以在values中 反向:按 表名小写,跨表可以在filter,也可以在values中 def findBookTyp2(request): # 查询东游记的所有作者名字 # 1.以Book为基表 ret = Book.objects.filter(name='东游记').values('authors__name') print(ret) # 2.以Author为基表 ret = Author.objects.filter(book__name='东游记').values('name') print(ret) return HttpResponse('findBookTyp2') <QuerySet [{'authors__name': 'jack'}, {'authors__name': 'ant'}]> <QuerySet [{'name': 'jack'}, {'name': 'ant'}]>3、连续跨表查询 一直用双下划线 __ 获取字段
def findBookTyp3(request): # 查询东游记这本书所有的作者的照片 book = Book.objects.filter(name='东游记').first() authors = book.authors.all() for author in authors: authordatil = author.authordatil print(authordatil.photo) # 方法二,使用连续跨表 ret = Book.objects.filter(name='东游记').values('authors__authordatil__photo') print(ret) return HttpResponse('findBookTyp3')结果:
www.baidu.com/author3.png www.baidu.com/author4.png <QuerySet [{'authors__authordatil__photo': 'www.baidu.com/author3.png'}, {'authors__authordatil__photo': 'www.baidu.com/author4.png'}]>当前文章用到的部分Code
