django之多表操作
django中模型表在Terminal中测试:python manage.py shell
一、表与表之间的关系
一对一:(OneToOneField) 关系字段无论建在哪张表里都可以,但是推荐建在查询频率比较高的那张表
【publish = models.ForeignKey(to='Publish')】--- django源码中,就是ForeignKey中unique=True
class OneToOneField(ForeignKey)
def __init__(self, to, on_delete=None, to_field=None, **kwargs):
kwargs['unique'] = True
一对多:(ForeignKey) 一对多字段建在多的那一方
多对多:(ManyToManyField) 多对多字段无论建在哪张关系表里都可以,但是推荐建在查询频率比较高的那张表
ps: 如何判断表与表之间到底什么关系
换位思考:A能不能有多个B
B能不能有多个A
增改删:可以是一个或多个 【数字,也可以是对象】
add() # 添加
set() # 修改
remove() #不能接收可迭代对象,可以* querySet对象
clear() # 清空 不用传参
删中设置级联删除:
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True) # 取消级联删除一定要设置null=True
CASCADE: 设置级联删除,即删除了出版社,对应的该出版社的书也会一块删除
SET_NULL: 取消级联删除
models:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8, decimal_places=2) publist_date = models.DateField(auto_now_add=True) # publish = models.ForeignKey(to='Publish', to_field='id', on_delete=models.CASCADE,) publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True) authors = models.ManyToManyField(to='Author') # 虚拟字段 class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=32) email = models.EmailField() # 对应就是varchar类型 class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() authordetail = models.OneToOneField(to='AuthorDetail') class AuthorDetail(models.Model): phone = models.CharField(max_length=32) addr = models.CharField(max_length=32)
增、改、删 操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# ----------------------------- # 多表查询 # 一对多的增改删 # 新增 # 直接写id # models.Book.objects.create(title='红楼梦', price=66.66, publish_id=1) # 传数据对象 # publist_obj = models.Publish.objects.filter(pk=2).first() # models.Book.objects.create(title='三国演义', price=199.99, publish=publist_obj) # 修改 # queryset修改[publish_id] # models.Book.objects.filter(pk=1).update(publish_id=3) # queryset修改[publish] # publish_obj2 = models.Publish.objects.filter(pk=2).first() # models.Book.objects.filter(pk=1).update(publish=publish_obj2) # 对象修改 # book_obj = models.Book.objects.filter(pk=3).first() # book_obj.publish_id = 1 # 点表中真实存在的字段名 # book_obj.save() # book_obj = models.Book.objects.filter(pk=3).first() # publish_obj = models.Publish.objects.filter(pk=3).first() # book_obj.publish = publish_obj # 点orm中字段名,传字段对应表的数据对象 # book_obj.save() # 删除 # models.Book.objects.filter(pk=1).delete() # models.Publish.objects.filter(pk=1).delete() # models.Publish.objects.filter(pk=7).delete() # 基于对象删除 # book_obj = models.Book.objects.filter(pk=8).first() # book_obj.delete() # 查询年 # res = models.Book.objects.filter(publist_date__year=2017) # for row in res: # print(row.title) # 查询名字包含字母n的用户 sqlite数据库大小写演示不出来 # res = models.Author.objects.filter(name__contains='n') # print(res) # res = models.Author.objects.filter(name__icontains='n') # print(res) #------------------------------------------------------- # 多对多之增删改 # 添加关系:add支持传数字或对象,并且都可以传多个 # 给书籍绑定与作者之间的关系 # 加数字 # book_obj = models.Book.objects.filter(pk=2).first() # book_obj.authors.add(1) # book_obj.authors.add(2, 3) # 加多个数字 # 传对象 # authors_obj = models.Author.objects.filter(pk=1).first() # book_obj = models.Book.objects.filter(pk=2).first() # book_obj.authors.add(authors_obj) # 传多个对象 # authors_obj1 = models.Author.objects.filter(pk=2).first() # authors_obj2 = models.Author.objects.filter(pk=3).first() # book_obj = models.Book.objects.filter(pk=2).first() # book_obj.authors.add(authors_obj1,authors_obj2 ) # 修改书籍与作者的关系 set() set传的必须是可迭代对象 # 可以传数字和对象,并且支持传多个 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.set((1,)) # 把id为2的书的作者改为1 # book_obj.authors.set((2,3)) # 把id为2的书的作者改为1 # 传多个对象 # book_obj = models.Book.objects.filter(pk=1).first() # author_list = models.Author.objects.all() # book_obj.authors.set(author_list) # 删除书籍与作者之间的关系 # book_obj = models.Book.objects.filter(pk=1).first() # 可以传数字和对象,并且支持多个 # book_obj.authors.remove(1) # book_obj.authors.remove(2, 3) # author_obj = models.Author.objects.all().first() # book_obj = models.Book.objects.filter(pk=2).first() # book_obj.authors.remove(author_obj) # author_list = models.Author.objects.all() # book_obj = models.Book.objects.filter(pk=2).first() # book_obj.authors.remove(*author_list) # 需要将queryset对象打散 # 清空 clear() # 清空的是当前这个表记录对应的绑定关系 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.clear()
正反向
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 基于对象的表查询 # 正向 # 查询书籍是西游记的出版社邮箱 # book_obj = models.Book.objects.filter(title='西游记').first() # print(book_obj.publish, type(book_obj.publish)) # publish_obj # print(book_obj.publish.email) # 查询书籍是python的作者的姓名 # book_obj = models.Book.objects.filter(title='红楼梦').first() # print(book_obj.authors) # app01.Author.None # print(book_obj.authors.all()) # 查询作者为jason的电话号码 # author = models.Author.objects.filter(name='jason').first() # print(author.authordetail.phone) # 反向 # 查询出版社是东方出版社的书籍 一对多的反向查询 # publish_obj = models.Publish.objects.filter(name="南方出版社").first() # print(publish_obj.book_set.all()) # 查询作者egon写过的所有书 多对多的反向查询 # author_obj = models.Author.objects.filter(name="egon").first() # print(author_obj.book_set) # app01.Book.None # print(author_obj.book_set.all(), type(author_obj.book_set.all())) # 查询作者电话号码是110的作者姓名 一对一的反向查询 # author_obj = models.AuthorDetail.objects.filter(phone='110').first() # print(author_obj.author) #作者的名字jason [__str__ 中定义的打印内容] # print(author_obj.author.name) # jason
下划线:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 基于双划线的正向查询 # 查询书籍为python的出版社地址 # res = models.Book.objects.filter(title='python').values('title', 'publish__addr') # print(res) # 查询书籍为西游记的作者的姓名 # res = models.Book.objects.filter(title='西游记').values('authors__name', 'title') # print(res) # 查询作者为jason的家乡 # res = models.Author.objects.filter(name='jason').values('authordetail__addr', 'name') # print(res) # 基于双划线的反向查询 # 查询南方出版社的所有书 # res = models.Publish.objects.filter(name='南方出版社').values('book__title', 'name') # print(res) # 查询电话号码为120的作者姓名 # res = models.AuthorDetail.objects.filter(phone='120').values('author__name') # print(res) # 查询作者为jason的写的书的名字 # res = models.Author.objects.filter(name='jason').values('book__title') # print(res) # 查询书籍为水浒传的作者的电话号码 # res = models.Book.objects.filter(title='水浒传').values('authors__authordetail__phone') # print(res) # 查询jason作者的手机号 # 正向 # res = models.Author.objects.filter(name='jason').values('authordetail__phone') # print(res) # 反向 # res = models.AuthorDetail.objects.filter(author__name='jason').values('phone') # print(res) # 查询出版社为东方出版社的所有的图书的名字和价格 # 正向 # res = models.Publish.objects.filter(name="东方出版社").values('book__title', 'book__price') # print(res) # 反向 # res = models.Book.objects.filter(publish__name='东方出版社').values('title', 'price') # print(res) # 查询东方出版社的价格大于19的书 # 正向 # res = models.Publish.objects.filter(name='东方出版社', book__price__gt=19) # res = models.Publish.objects.filter(name='东方出版社', book__price__gt=19).values('book__title', 'book__price') # print(res) # 反向 # res = models.Book.objects.filter(publish__name='东方出版社', price__gt=19).values('title', 'price') # print(res)
聚合(aggregate)、分组(annotate类比为group by):
from django.db.models import Count, Avg, Min, Sum,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
# 聚合查询 aggregate from django.db.models import Count, Avg, Min, Sum # 查询书籍对应的作者人数 # res = models.Book.objects.filter(pk=2).aggregate(authors_num=Count('authors')) # print(res) # 查询所有出版社书的平均价格 # res = models.Publish.objects.aggregate(price_avg=Avg('book__price')) # print(res) # 统计东方出版社出版的书籍的个数 # res = models.Publish.objects.filter(name='南方出版社').aggregate(book_num=Count('book')) # print(res) # 分组查询annotate 相当于group by # 查询没个出版社出的书的平均价格 # res = models.Publish.objects.annotate(price_avg=Avg('book__price')).values('name', 'price_avg') # print(res) # 统计每本书的作者个数 # res = models.Book.objects.annotate(authors_num=Count('authors')).values('title', 'authors_num') # print(res) #统计每个出版社最便宜的书 # res = models.Publish.objects.annotate(price_min=Min('book__price')).values('price_min') # print(res) # 查询每个作者出书的总价格 # res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name', 'price_sum') # print(res)
正向与反向的概念
【小结】 1. 正向查询按字段,反向查询按表名小写 【同样适用于双下划线之values()参数】
2. 当被跨的表的中可能有多个数据时,就表名小写_set.all()
3. 基于对象【对象点语法】查询类比为子查询, 基于下划线的可类比成链表
4. author_obj.book_set # 输出结果app01.Book.None,
author_obj.book_set.all() # queryset对象
一对一
正向:author---关联字段在author表里--->authordetail 按字段
反向:authordetail---关联字段在author表里--->author 按表名小写
查询jason作者的手机号 正向查询
查询地址是 :山东 的作者名字 反向查询
一对多
正向:book---关联字段在book表里--->publish 按字段
反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书
多对多
正向:book---关联字段在book表里--->author 按字段
反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书
# 反向
# 查询出版社是东方出版社的书籍 一对多的反向查询
# publish_obj = models.Publish.objects.filter(name="南方出版社").first()
# print(publish_obj.book_set.all())
# 查询作者egon写过的所有书 多对多的反向查询
# author_obj = models.Author.objects.filter(name="egon").first()
# print(author_obj.book_set) # app01.Book.None
# print(author_obj.book_set.all())
# 查询作者电话号码是110的作者姓名 一对一的反向查询
# author_obj = models.AuthorDetail.objects.filter(phone='110').first()
# print(author_obj.author) #作者的名字jason [__str__ 中定义的打印内容]
# print(author_obj.author.name) # jason