57 ORM多表查询

多表查询
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)

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',)


一.添加表记录

1.一对多(book表和publish表)
创建python书,给该书绑定人民出版社,以及两个作者alex,egon(假设alex的id=1,egon的id=2)

方式一:(publish为对象时,直接传对象的方式,publish = publish某对象)

publish_1 = models.Publish.objects.filter(name="人民出版社").first()
egon = models.Author.objects.filter(name="egon").first()
alex = models.Author.objects.filter(name="alex").first()
book = models.Book.objects.create(title="python",price=333,pub_date="2017-12-12",publish=publish_1)



方式二:(已知publish的id时,假设要添加的publish的id为 publish_id=1)
book = models.Book.objects.create(title="python",price=333,pub_date="2017-12-12",publish_id=1)


2.多对多关系(book表和author表)
book.authors.add(egon,alex) 对象方式添加
或 book.authors.add(1,2) 直接添加id 也可以
或 book.authors.add(*[1,2]) 通过列表的方式添加,用*打散添加
book.authors.remove(egon) 移除关系
book.authors.clear() 清空关系
book.authors.set([1,2]) set 的效果时先清空,后添加,里面的必须传一个列表


二.基于对象的跨表查询(相当于sql中的子查询)

key:
1正向查询按关联字段,反向查询按表名小写
2.正向,指的是关联字段所在的表,开始查


一对一查询(Author 和 AuthorDetail)

1.正向查询(按字段:authorDetail)
egon = Author.objects.filter(name="egon").first()
print(egon.authorDetail.telephone)

2.反向查询(按表名:author)
查询所住地址在北京的作者的姓名
authorDetail.objects.filter(addr="北京”)
for obj in authorDetail_list:
print(obj.author.name)

多对多查询(author和book)
1.正向查询(按字段:authors):
python 所有作者的名字和手机号
python = Book.objects.filter(title="python").first()
authors = python.authors.all()
for author in authors:
print(author.name)
print(author.authorDetail.telephone)

2.反向查询(按表名小写 :book_set, set表示集合)
查询egon 出过的所有书籍的名字
egon= Author.objects.filter(name="egon").first()
book_lst= egon.book_set.all()
for book_obj in book_lst:
print(book_obj.name)


三.基于双下划线的跨表查询(相当于mysql中join语句)
key:
1.双下滑线代表跨表
2.双下滑线查询结构: 表名.filter(条件).vaules(需要查询的字段)

1.一对多查询
查出苹果出版社出版过的所有书籍的名字和价格

1.正向查询 (按字段:publish)
queryset = Book.objects.filter(publish__name="苹果出版社").vaules("title","price")

2.反向查询(按表名:book)
queryset = Publish.objects.filter(name="苹果出版社").vaules("book__title","book__price")

2.多对多查询(author和book)

查询 egon 出过的所有书籍的名字

正向查询按字段:(authors)
queryset = Book.objects.filter(authors__name="egon").vaules("title")

反向查询 按表名小写book
queryset = Author.objects.filter(name="egon").vaules("book__price")

3. 一对一 查询
查询alex 的手机号

正向查询:
ret = Author.objects.filter(name="alex").vaules("authorDetail__telphone")

反向查询:
ret = AuthorDetail.objects.filter("author__name="alex").vaules("telephone")


四.连续跨表查询

1.查询人民出版社出版过的所有书籍的名字以及作者的姓名
正向查询:
queryset = Book.objects.filter(publish__name="人民出版社").vaules("title","author__name")

反向查询:
queryset = Publish.objects.filter(name="人民出版社").vaules.("book__title","book__authors__name")

2. 手机号以17开头的作者出版过的所有书籍名称以及出版社名称

方式1:
queryset = Book.objects.filter(authors__authordetail__telphone__startswith="17").vaules("title","publish__name")

方式2:
ret = Author.objects.filter(authorDetail__telphone__startswith="17").vaules("book__title","book__publish__name")

五.聚合查询与分组查询

1.聚合

1.需要先引入聚合函数
from django.db.models import Avg,Max,Min,Count

2. aggregate(*args, **kwargs)
aggregate 的返回值是一个字典,键的名称是聚合值的标识符
计算所有图书的平均价格,最大价格,最小价格:
默认方式:
dic = Book.objects.all().aggregate(Avg('price'))
print(dic) #{"price_avg":34}
自定定义键值方式:
dic = Book.objects.all().aggregate(avg_price = Avg("price"),max_price=Max('price'), min_price = Min('price'))


2.分组
1.单表分组查询

emp:

id name age salary dep
1 alex 12 2000 销售部
2 egon 22 3000 人事部
3 wen 22 5000 人事部

查询每个部门名称以及对应的员工数:
sql语句:
select dep,count(*) from emp group by(dep)
ORM:
emp.objects.vaules("dep").annotate(c=Count("id"))

2.多表分组查询
key:
1.annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。

2.跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询。
3.annotate的返回值是querySet,如果不想遍历对象,可以用上valuelist
4.格式 : 分组的对象.objects.annotate(函数).vaules(需要的值1,函数结果)
ret = Publish.objects.annotate(min_price=min("price")).vaules("name","min_price")
emp:

id name age salary dep_id
1 alex 12 2000 1
2 egon 22 3000 2
3 wen 22 5000 2


dep

id name
1 销售部
2 人事部

查询每一个部门名称以及对应的员工数
sql:
select dep.name,count(*) from emp left join dep on emp.dep_id=dep.id group by dep.id

ORM:
dep.objects.vaules("id").annotate(c = count("emp")).vaules("name","c")


查询练习:

1.统计每一个出版社的最便宜的书
publish_lst = Publish.objects.annotate(min_price = Min("book__price"))
for publish_obj in publish_lst:
print(publish_obj.name,publish_obj.minprice)

annotate的返回值是querySet,如果不想遍历对象,可以用上values
ret = Publish.objects.annotate(min_price=min("price")).vaules("name","min_price")

2.统计每一本书的作者个数
ret = Book.objects.annotate(authorsNum=Count("authors__name"))

3.统计每本书以py开头的书籍的作者个数
ret = Book.objects.filter(title__startswith="py").annotate(c=count("authors__name"))


4.统计不止一个作者的图书

queryset = book.objects.annotate(c = count(”authors")).filter(c__gt=1)

5.根据一本书的作者数量多少对查询集queryset进行排序
book.objects.annotate(c=count(”authors")).order_by ("c")

6.查询各个作者出的书的总价格
Author.objects.annotate(sum_price = Sum("book__price")).vaules("name","sum_price")


六 F查询与Q查询

1.F查询
1. 先导入 from django.db.models import F
2.Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。
3.修改操作也可以使用F函数

1.查询评论数大于收藏数的书籍
Book.objects.filter(comment_num__gt = F("keepnum"))
2.查询评论数大于收藏数2倍的书籍
Book.objects.filter(comment_num__gt=F("keepnum")*2)

3.将每一本书的价格提高30元
Book.objects.all().update(price=F("keepnum")+30)



2.Q查询 :在filter 多条件查询时,
1.导入 from django.db.models import Q

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

3.Q 对象可以使用&(且) 和|(或) 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
等同sql中:WHERE name ="yuan" OR name ="egon"

4.查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。
但是,如果出现Q 对象,它必须位于所有关键字参数的前面。
bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),title__icontains="python)




















猜你喜欢

转载自www.cnblogs.com/knighterrant/p/10235473.html
57
今日推荐