django系列5.3--ORM数据库的多表操作
首先来创建一个模型,数据库的关系就清楚了
models.py
from django.db import models # Create your models here. class Author(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() au = models.OneToOneField(to='AuthorDetail',to_field='id',on_delete=models.CASCADE) class AuthorDetail(models.Model): id = models.AutoField(primary_key=True) address = models.CharField(max_length=32) tel = models.CharField(max_length=11) class Publish(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=22) addr = models.CharField(max_length=64) class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) publisher = models.ForeignKey(to='Publish',to_field='id',on_delete=models.CASCADE) authors = models.ManyToManyField(to='Author')
一.创建模型
一对一创建
obj = models.onetooneField(to='表名', to_Field='字段')
一对多创建
obj = models.Foreignkey(to='表名', to='字段名', on_delete=models.CASCADE)
多对多创建
obj = models.manytomanyField(to='表名')
二.添加数据
一对一添加
models.Author.objects.create( name = '太宰治', age = 18, author_id = 1 )
一对多添加
方式1, 用对象的方式创建
publish_obj = Publisht.objects.get(id=1) # 拿到id为1的出版社对象 book_obj = Book.objects.create( title='人间失格', publish = publish_obj, )
方式2, 直接指定字段名称创建
book_obj = Book.objects.create( title='人间失格', publish_id=1, )
多对多添加
方式1
book_obj = models.Book.objects.filter(id=4)[0] lzs = models.Author.objects.get(id=1) ws = models.Author.objects.get(id=2) book_obj.authors.add(lzs,ws)
方式2
book_obj.authors.add(*[1,2])
book_obj.authors.add(1,2)
其他常用API:
book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除。 book_obj.authors.remove(*[1,2]),将多对多的关系数据删除 book_obj.authors.clear() #清空被关联对象集合 book_obj.authors.set() #先清空再设置(更新)
三.删除数据
一对一、一对多的删改和单表的删改是一样的,因为在models里面我们设置了级联删除
models.Author.objects.filter(id=1).delete() models.Book.objects.filter(id=1).delete() book_obj.authors.clear() book_obj.authors.remove('2')
多对多删除,用到的
book_obj.authors.remove()
三.基于对象的跨表查询
正向查询与反向查询
外键字段在哪个表中,它找别人就是正向查询
别的表找它就是反向查询
一对一查询(Author表和AuthorDetail):
正向查询按字段,反向查询用表名小写
1 查询名为太宰治的作者的电话号码 ret = models.Author.objects.get(name='太宰治') models.Author.objects.get(name='太宰治').au.address models.Author.objects.filter(name='太宰治')[0].au.address a = ret.au.tel 2 查询电话号码为111的作者的名称 ret = models.AuthorDetail.objects.get(tel=111) a = ret.author.name
一对多查询(Publish表与Book表)
正向查询按字段,反向查询用表名小写_set.all()
正向查询:
# 查询主键为1的书籍的出版社所在的城市 book_obj=Book.objects.filter(pk=1).first() # book_obj.publish 是主键为1的书籍对象关联的出版社对象,book对象.外键字段名称 print(book_obj.publish.city)
反向查询: book_set().all()
publish=Publish.objects.get(name="太阳出版社") #publish.book_set.all() : 与苹果出版社关联的所有书籍对象集合,写法:小写的表名_set.all(),得到queryset类型数据 book_list=publish.book_set.all() for book_obj in book_list: print(book_obj.title)
多对多查询:(Author表和Book表)
正向查询
# 人间失格所有作者的名字以及手机号 book_obj=Book.objects.filter(title="人间失格")[0] authors=book_obj.authors.all() for author_obj in authors: print(author_obj.name,author_obj.authorDetail.telephone)
反向查询
# 查询太宰治出过的所有书籍的名字 author_obj=Author.objects.get(name="太宰治") book_list=author_obj.book_set.all() #与太宰治作者相关的所有书籍 for book_obj in book_list: print(book_obj.title)
四.基于双下划线的跨表查询
相当于基于join的联表查询,效率较高,用法是正向按属性(models.py中定义的),反向按表名.
一对一查询
#查询太宰治的手机号 #正向查询 ret=Author.objects.filter(name="太宰治").values("au__tel") #反向查询 ret=AuthorDetail.objects.filter(author__name="太宰治").values("tel")
一对多查询
查询太阳出版社出版过的所有书籍的名字与价格(一对多) # 正向查询 按字段:publish queryResult=Book.objects.filter(publish__name="太阳出版社").values_list("title","price") #values或者values_list #通过__告诉orm将book表和publish表进行join,然后找到所有记录中publish.name='苹果出版社'的记录(注意publish是属性名称),
然后select book.title,book.price的字段值 # 反向查询 按表名:book queryResult=Publish.objects.filter(name="太阳出版社").values_list("book__title","book__price")
多对多查询
#查询太宰治出过的所有书籍的名字(多对多) # 正向查询 按字段:authors: queryResult=Book.objects.filter(authors__name="太宰治").values_list("title") # 反向查询 按表名: bookqueryResult=Author.objects.filter(name="太宰治").values_list("book__title","book__price")
五.修改数据
修改数据使用update() 用queryset类型来调用
models.Book.objects.filter(title='太宰治').update(title='村上春树')
修改多对多对象的关系
models.Book.objects.filter(title='太宰治')[0].set(*[1,2])