orm多表操作

创建实验数据库library

实例:我们来假定下面这些概念,字段和关系
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版商模型:出版商有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。

from django.db import models
# Create your models here.
#作者表
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    age=models.IntegerField()

    # 与AuthorDetail建立一对一的关系
    authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE) #on_delete=models.CASCADE级联删除,默认就是这个
#作者详情表
class AuthorDetail(models.Model):

    nid = models.AutoField(primary_key=True)
    birthday=models.DateField()
    telephone=models.BigIntegerField()
    addr=models.CharField( max_length=64)

#出版社表
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()

#书籍表
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建立一对多的关系,外键字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
    authors=models.ManyToManyField(to='Author',)

添加表记录

操作前先录入一些数据:
publish表



author表



authordetail表
一对多

方式1:

 publish_obj=Publish.objects.get(nid=1)
 book_obj=Book.objects.create(title="皮皮历险记",publishDate="2012-12-12",price=100,publish=publish_obj)

方式2:

book_obj=Book.objects.create(title="东东历险记",publishDate="2012-12-12",price=100,publish_id=1) 
多对多

方式1

# 当前生成的书籍对象
book_obj=Book.objects.create(title="狼图腾",price=200,publishDate="2012-11-12",publish_id=2)
# 为书籍绑定的做作者对象
lx=Author.objects.filter(name="鲁迅").first() # 在Author表中主键为2的纪录
gy=Author.objects.filter(name="关羽").first() # 在Author表中主键为4的纪录

# 绑定多对多关系,即向关系表book_authors中添加纪录
book_obj.authors.add(lx,gy)    #  将某些特定的 model 对象添加到被关联对象集合中。   =======    book_obj.authors.add(*[])

方式二

book_obj=Book.objects.create(title="狗图腾",price=200,publishDate="2012-11-12",publish_id=2)
#直接写Author的主键
book_obj.authors.add(1,2) #或者 book_obj.authors.add(*[1,2])

book表



book_authors表



多对多其他常用的方法
book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[])
book_obj.authors.clear()       #清空被关联对象集合
book_obj.authors.set()         #先清空再设置 

基于对象的跨表查询

一对多查询(Publish 与 Book)

正向查询(按字段:publish):

# 查询主键为1的书籍的出版社所在的城市
book_obj=Book.objects.filter(pk=1).first()
# book_obj.publish 是主键为1的书籍对象关联的出版社对象
print(book_obj.publish.city) 

反向查询(按表名:book_set)

publish = Publish.objects.get(name="清华大虚出版色")
# publish.book_set.all() : 与清华大虚出版色关联的所有书籍对象集合,表名小写_set.all()
book_list = publish.book_set.all()
for book_obj in book_list:
     print(book_obj.title)
一对一查询(Author 与 AuthorDetail)

正向查询(按字段:authorDetail)

#查询张飞的电话号码
zf = Author.objects.filter(name="张飞").first()
print(zf.authorDetail.telephone)

反向查询(按表名:author)

# 查询所有住址在北京的作者的姓名
authorDetail_list=AuthorDetail.objects.filter(addr="北京")
for obj in authorDetail_list:
     print(obj.author.name)
多对多查询 (Author 与 Book)

正向查询(按字段:authors)

#查询狗图腾的所有作者和电话
book_obj = Book.objects.filter(title="狗图腾").first()
authors = book_obj.authors.all()
for author_obj in authors:
     print(author_obj.name, author_obj.authorDetail.telephone)

反向查询(按表名:book_set)

# 查询张飞出过的所有书籍的名字
author_obj = Author.objects.get(name="张飞")
book_list = author_obj.book_set.all()  # 与张飞作者相关的所有书籍
for book_obj in book_list:
    print(book_obj.title)

注意:
你可以通过在 ForeignKey() 和ManyToManyField的定义中设置 related_name 的值来覆写 FOO_set 的名称。例如,如果 Article model 中做一下更改:

publish = ForeignKey(Book, related_name='bookList')

那么接下来就会如我们看到这般:

# 查询 人民出版社出版过的所有书籍
publish=Publish.objects.get(name="人民出版社")
book_list=publish.bookList.all()  # 与人民出版社关联的所有书籍对象集合

基于双下划线的跨表查询

一对多查询

正向查询 按字段:publish

#查询清华大虚出版色出版过的所有书籍的名字与价格(一对多)
queryResult = Book.objects.filter(publish__name="清华大虚出版色").values_list("title", "price").all()
for q in queryResult:
    print(q)

反向查询 按表名:book

queryResult = Publish.objects.filter(name="清华大虚出版色").values_list("book__title", "book__price").all()
for q in queryResult:
    print(q)
多对多查询

正向查询 按字段:authors

#查询鲁迅出过的所有书籍的名字(多对多)
queryResult = Book.objects.filter(authors__name="鲁迅").values_list("title").all()
for q in queryResult:
    print(q)

反向查询 按表名:book

queryResult = Author.objects.filter(name="鲁迅").values_list("book__title", "book__price")
for q in queryResult:
    print(q)
一对一查询

正向查询

#查询关羽的手机号
ret = Author.objects.filter(name="关羽").values("authorDetail__telephone").first()
print(ret)

反向查询

 ret = AuthorDetail.objects.filter(author__name="关羽").values("telephone")
 print(ret.first())

连续跨表

正向查询

# 查询人民日报出版社出版过的所有书籍的名字以及作者的姓名
queryResult = Book.objects.filter(publish__name="人民日报出版社").values_list("title", "authors__name")
print(queryResult)

反向查询

 queryResult = Publish.objects.filter(name="人民日报出版社").values_list("book__title", "book__authors__age", "book__authors__name")
 print(queryResult)

聚合查询与分组查询

聚合

计算所有图书的平均价格

from django.db.models import Avg
p=Book.objects.all().aggregate(Avg('price'))
print(p)
{'price__avg': 150.0}

#aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
Book.objects.aggregate(average_price=Avg('price'))
{'average_price': 34.35}

#如果你希望生成不止一个聚合,你可以向aggregate()子句中添加另一个参数。所以,如果你也想知道所有图书价格的最大值和最小值,可以这样查询:
from django.db.models import Avg,Max,Min
p=Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
print(p)
{'price__avg': 150.0, 'price__max': Decimal('200.00'), 'price__min': Decimal('100.00')}
分组

单表分组
查询书籍表每一个出版社的id以及对应的书籍个数

#key: annotate()前select哪一个字段就按哪一个字段group by
#select Count(1) from book group by publish_id;
g=Book.objects.values("publish_id").annotate(c=Count(1))
print(g)

多表分组
查询书籍表每一个出版社的名字以及对应的书籍个数

g = Book.objects.values("publish__name").annotate(c=Count(1))
print(g)

查询每个作者出的最贵的书的价格

ret=Author.objects.annotate(maxprice=Max("book__price")).values('name',"maxprice")
print(ret)

查询作者数不等于一的书籍

ret=Book.objects.annotate(c=Count("authors")).filter(c__gt=1).values("title","c")
print(ret)

根据一本图书作者的数量查询集合QuerySet进行排序,'-'代表反向排序

ret = Book.objects.annotate(c=Count("authors__name")).order_by("-c").values("title","c")
print(ret)

统计每一本以图腾结尾的书籍名称和作者个数

ret = Book.objects.filter(title__endswith="图腾").annotate(c=Count("authors__name")).values("title","c")
print(ret)

F查询

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

给book表添加两个字段,评论数pinglun,点赞数dianzan

dianzan=models.IntegerField(default=0)
pinglun = models.IntegerField(default=0)

查询点赞数小于评论数的书籍

 from django.db.models import F
 ret=Book.objects.filter(dianzan__lt=F('pinglun')).values("title")
 print(ret)

查询评论数大于2倍点赞数的书籍

from django.db.models import F
ret = Book.objects.filter(pinglun__gt=F('dianzan')*2).values("title")
print(ret)

修改操作也可以使用F函数,比如将每一本书的价格提高30元

Book.objects.all().update(price=F("price")+30)

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象。

from django.db.models import Q
Q(title__startswith='Py')

Q 对象可以使用& 和| 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

查询作者是张飞或者是关羽的书籍

 bookList = Book.objects.filter(Q(authors__name="张飞") | Q(authors__name="关羽")).values("title")
 print(bookList)

你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询:

bookList=Book.objects.filter(Q(authors__name="关羽") & ~Q(publishDate__year=2017)).values_list("title")

多个Q嵌套
查询价格大于250块并且点赞大于一千的 或者 评论小于100的书

bookList = Book.objects.filter(Q(Q(price__gt=259) & Q(dianzan__gt=1000)) | Q(pinglun__lt=100)).values_list("title")
print(bookList)

查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。例如:

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

推荐阅读更多精彩内容

  • ForeignKey操作 源数据表: 表Mypublisher与Mybook是一对多的关系,我们一般是在多的一方建...
    雨中寻雾阅读 207评论 0 1
  • ORM多表操作 一、创建表模型 二、一对多 添加表记录: 删除表记录: 修改表记录: 三、多对多 add:可以传对...
    knot98阅读 296评论 0 0
  • Django 中有一个强大的功能,就是ORM,他可以不写sql语句,使用python语法,即可操作数据库。当然也有...
    清风徐来_简阅读 420评论 0 1
  • 表关系总结: 跟SQL的 关系 一样。注意在一对多中,应该把外键定义在多的当中。 一对一:models.OneTo...
    别动我名字呀阅读 440评论 0 1
  • 前言 Django框架功能齐全自带数据库操作功能,本文主要介绍Django的ORM框架 https://www.c...
    许华锋阅读 1,919评论 0 0