10_ORM多表操作

ORM多表操作

一、创建表模型

class Publish(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
    email = models.EmailField()


class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    sex = models.IntegerField()
    authordetail = models.OneToOneField(to='AuthorDetail', to_field='id')


class AuthorDetail(models.Model):
    id = models.AutoField(primary_key=True)
    phone = models.CharField(max_length=32)
    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')
    authors = models.ManyToManyField(to=Author)

二、一对多

添加表记录:
# 方式一
publish_obj=Publish.objects.get(id=1)
book_obj=Book.objects.create(name='龙族',price=99,publish=publish_obj)

# 方式二
 book_obj=Book.objects.create(name='龙族',price=99,publish_id=1)

"""
    publish = 对象
    publish_id = id
"""
删除表记录:
# 同单表删除,查询出想要删除的对象 .delete()
Book.objects.all().delete()
修改表记录:
# 方式一
book=Book.objects.get(pk=1)
book.publish=publish_obj
book.publish_id=2
book.save()

# 方式二
book=Book.objects.filter(pk=1).update(publish=publish_obj)
book=Book.objects.filter(pk=1).update(publish_id=1)

三、多对多

  • add:可以传对象,可以传id,可以传多个
  • remove:可以传对象,可以传id,可以传多个
  • clear:没有参数
  • set:跟上面不一样,必须传列表,列表里面可以是对象,可以是id
# 为龙族添加hgq、hhh两个作者
hgq=Author.objects.filter(name='hgq').first()
hhh=Author.objects.filter(name='hhh').first()
book=Book.objects.filter(name='龙族').first()
# add 添加多个对象
book.authors.add(hgq,hhh)

# 删除 remove,可以传对象,可以传id,可以传多个,不要混着用
book.authors.remove(1)

# clear清空所有
book.authors.clear()

# set,先清空,在新增,要传一个列表,列表内可以是, id,也可以是对象
book.authors.set(*[hgq,])

四、基于对象的跨表查询(子查询)

一对一:
# 正向  查询作者hgq的手机号 
author=Author.objects.filter(name='hgq').first()
# author.authordetail 就是作者详情的对象
authordetail=author.authordetail
print(authordetail.phone)

# 反向  查询地址是: 上海 的作者名字
authordetail=AuthorDetail.objects.filter(address='上海').first()
# authordetail.author  这是作者对象
author=authordetail.author
print(author.name)
一对多:
# 正向:正向查询按字段  查询龙族这本书的出版
book=Book.objects.filter(name='龙族').first()
# book.publish  就是出版社对象
pulish=book.publish
print(pulish.email)

# 反向:反向按表名小写_set.all()  查询地址是北京 的出版社出版的图书
publish=Publish.objects.filter(address='北京').first()
# publish.book_set.all()  拿出所有的图书
books=publish.book_set.all()
count():
# 统计一下条数
books=publish.book_set.all().count()
print(books)
多对多:
# 正向:正向查询按字段   查询龙族这本书所有的作者
book=Book.objects.filter(name='龙族').first()
# book.authors.all()  是所有的作者,是一个queryset对象,可以继续点 
print(book.authors.all())
    
# 反向查询:反向按表名小写_set.all()  查询hgq写的所有书
hgq=Author.objects.filter(name='hgq').first()
books=hgq.book_set.all()
print(books)

五、基于双下划线的跨表查询

  • 连表查询
# 查询龙族这本书所有的作者的手机号
book=Book.objects.filter(name='龙族').first()
authors=book.authors.all()
for author in authors:
    authordetail=author.authordetail
    print(authordetail.phone)
  • 一对一双下划线查询
    • 正向:按字段,跨表可以在filter,也可以在values中
    • 反向:按表名小写,跨表可以在filter,也可以在values中
# 查询hgq作者的手机号   
# 以author表作为基表,正向查询,跨表的话,按字段
ret=Author.objects.filter(name='hgq').values('authordetail__phone')
print(ret)
# 以authordetail作为基表,反向查询,按表名小写,跨表的话,用表名小写
ret=AuthorDetail.objects.filter(author__name='hgq').values('phone')
print(ret)
  • 一对多双下划线查询
# 查询出版社为北京出版社出版的所有图书的名字,价格
ret = Book.objects.filter(name='北京出版社').values('book__name','book__price')
print(ret)
ret=Book.objects.filter(publish__name='北京出版社').values('name','price')
print(ret)
  • 多对多双下划线查询
# 查询红楼梦的所有作者名字
ret=Book.objects.filter(name='红楼梦').values('authors__name')
print(ret)
ret=Author.objects.filter(book__name='红楼梦').values('name')
print(ret)
  • 进阶练习--连续跨表
# 查询北京出版社出版过的所有书籍的名字以及作者的姓名
ret=Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name')
print(ret)

六、聚合查询--aggregate

聚合函数:
from django.db.models import Avg,Count,Max,Min,Sum
# 他是queryset的终止子句
# 计算所有图书的平均价格
ret=Book.objects.all().aggregate(Avg('price'))
print(ret)

# 计算图书的最高价格
ret=Book.objects.all().aggregate(Max('price'))
print(ret)

# 计算图书的最高价格,最低价格,平均价格,总价
ret=Book.objects.all().aggregate(Max('price'),Min('price'),Avg('price'),Sum('price'))
print(ret)

七、分组查询--annotate

annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。
总结 :跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询。
# 统计每一本书作者个数
ret=Book.objects.all().annotate(c=Count('authors'))
# 以每本书作者的个数进行分组,得到一个作者对象
print(ret)
for r in ret:
    print(r.name,'---->',r.c)
总结: group by 谁,就以谁做基表,filter过滤,annotate取分组,values取值
  • 终极总结:
    • values在前,表示group by,在后,表示取值
    • filter在前,表示过滤(where),在后,表示having(对分组之后的结果再进行过滤)

八、F查询与Q查询

F函数:为了字段=后面的值,不能放字段,所以用F函数包裹一下就可以了
from django.db.models import F
# 查询评论数大于阅读数的书
# 这样不行,进行不下去了,使用F函数包裹一下('read_num')
# ret=Book.objects.all().filter(commit_num__gt=read_num)
# 这么来做
ret=Book.objects.all().filter(commit_num__gt=F('read_num'))
print(ret)
Q函数:为了构造与&,或|,非~的关系
from django.db.models import Q
# 查询作者名字是lqz或者名字是egon的书
# 这样行不通
# ret=Book.objects.all().filter(authors__name='lqz',authors__name='egon')
# 这样出来
ret=Book.objects.all().filter(Q(authors__name='lqz')|Q(authors__name='egon'))
print(ret)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容