昨日回顾
1 多表关联的表模型
-author_detail=models.OneToOneField(to='AuthorDetail',to_field='id',)
-publish = models.ForeignKey(to=Publish,on_delete=models.CASCADE) # 虽然此处写的叫publish但是转到数据库中变成了publish_id
-authors=models.ManyToManyField(to='Author') # 自动创建第三张表
2 on_delete
-级联删除 # 级联删除用在哪,例如果要是删除出版社把出版社所有的书都删了,此时在这种表中就不能设置成级联删除;如果删除作者,删除作者详情,此时可以设置成级联删除
-设置为空
-设置为默认值
3 关联关系和外键,没有必然联系,关联关系是为了查询,外键是为了约束,防止出现脏数据 # 不建外键:在foreignKey,OneToOneField,ManyToManyField的后面设置db_constains=False,那么数据库中就没有外键那条线,即约束条件没有(一般是在代码中自己先过滤掉了),但是他们之间的关联关系还存在,其他的使用方法不变。
4 一对一,一对多的新增
-book.publish # 出版社对象
-新增一本书:Book.objects.create(...,publish=对象)
-新增一本书:Book.objects.create(...,publish_id=对象.id)
5 基于对象的跨表查询(子查询,多句sql)
-book=models.Book.objects.get(name='西游记')
-book.publish
-book.publish_id # publish_id这个字段就在book表中,如果写成publish.id也可以完成,但是相当于连了表publish查询id,多查询了一次数据库,此处相当于进行了sql优化
-publish=Publish.object.filter(id=book.publish_id)
-正向:直接字段
-反向:一条是表名小写,多条是表名小写_set.all()
6 基于双下划线的跨表查询(连表查询)
-filter,values,vlues_list中写 __ 双下划线就表示连表
- 正向:字段名
- 反向:表名小写(没有_set)
今日内容
0 前后端分离和混合开发
1 模板语言:每个语言的web框架都会有模板语言,django---》dtl
2 模板语言的渲染,是在后端完成的
3 用php写前端(前端只能用html,css,js其他的用不了)-----(不对)
php写的是模板语言,就跟django写的模板语言一样,是模板渲染,php一般写前后端混合开发
4 前后端分离:前后端交互,统一全用json格式,前端只专注于写前端(vue(国内用的多),react(大厂一般用的多):前端工程化),后端只专注于写后端(提供接口,交互json格式数据)
1 聚合查询
###########1 聚合查询(聚合函数:最大,最小,和,平均,总个数)
from django.db.models import Avg,Max,Min,Count,Sum # 需要先导入 aggregate 表示聚合函数
#1 计算所有图书的平均价格
# aggregate结束以后已经不是queryset对象了
# book=models.Book.objects.all().aggregate(Avg('price'))
# 起别名
# book=models.Book.objects.all().aggregate(avg=Avg('price'))
#2 计算总图书数
# book = models.Book.objects.all().aggregate(count=Count('id'))
# 3 计算最低价格的图书
# book = models.Book.objects.all().aggregate(min=Min('price'))
# 4 计算最大价格图书
# book = models.Book.objects.all().aggregate(max=Max('price'))
# print(book)
2 分组查询
####2 分组查询 # annotate
'''
查询每一个部门名称以及对应的员工数
book:
id name price publish
1 金品 11.2 1
2 西游 14.2 2
3 东游 16.2 2
4 北邮 19.2 3
'''
# 示例一:查询每一个出版社id,以及出书平均价格
# select publish_id,avg(price) from app01_book group by publish_id;
# annotate() 内写聚合函数
# values在前表示group by的字段
# values在后表示取某几个字段,在分组之后能取的字段有聚合函数的字段以及分组那个表中的所有字段
# filter在前表示where
# filter在后表示having
# from django.db.models import Avg, Count, Max, Min
# ret=models.Book.objects.values('publish_id').annotate(avg=Avg('price')).values('publish_id','avg')
# print(ret)
# 查询出版社id大于1的出版社id,以及出书平均价格
# select publish_id,avg(price) from app01_book where publish_id>1 group by publish_id;
# ret=models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).values('publish_id','avg')
# print(ret)
# 查询出版社id大于1的出版社id,以及出书平均价格大于30的
# select publish_id,avg(price)as aaa from app01_book where publish_id>1 group by publish_id HAVING aaa>30;
# ret = models.Book.objects.values('publish_id').filter(publish_id__gt=1).annotate(avg=Avg('price')).filter(avg__gt=30).values(
# 'publish_id', 'avg')
# print(ret)
## 查询每一个出版社出版的书籍个数
# pk 代指主键
# ret=models.Book.objects.get(pk=1)
# print(ret.name)
# ret=models.Publish.objects.values('pk').annotate(count=Count('book__id')).values('name','count')
# print(ret)
# 如果没有指定group by的字段,默认就用基表(Publish)主键字段作为group by的字段
# ret=models.Publish.objects.annotate(count=Count('book__id')).values('name','count')
# print(ret)
# 另一种方式实现
# ret=models.Book.objects.values('publish').annotate(count=Count('id')).values('publish__name','count')
# print(ret)
#查询每个作者的名字,以及出版过书籍的最高价格(建议使用分组的表作为基表)
# 如果不用分组的表作为基表,数据不完整可能会出现问题
# ret=models.Author.objects.values('pk').annotate(max=Max('book__price')).values('name','max')
# ret = models.Author.objects.annotate(max=Max('book__price')).values('name', 'max')
# ret= models.Book.objects.values('authors__id').annotate(max=Max('price')).values('authors__name','max')
# print(ret)
#查询每一个书籍的名称,以及对应的作者个数
# ret=models.Book.objects.values('pk').annotate(count=Count('authors__id')).values('name','count')
# ret=models.Book.objects.annotate(count=Count('authors__id')).values('name','count')
# ret=models.Author.objects.values('book__id').annotate(count=Count('id')).values('book__name','count')
#
# print(ret)
#统计不止一个作者的图书
# ret=models.Book.objects.values('pk').annotate(count=Count('authors__id')).filter(count__gt=1).values('name','count')
# ret = models.Author.objects.values('book__id').annotate(count=Count('id')).filter(count__gt=1).values('book__name', 'count')
# print(ret)
# 统计价格数大于10元,作者的图书
ret = models.Book.objects.values('pk').filter(price__gt=10).annotate(count=Count('authors__id')).values('name','count')
print(ret)
#统计价格数大于10元,作者个数大于1的图书
ret = models.Book.objects.values('pk').filter(price__gt=10).annotate(count=Count('authors__id')).filter(count__gt=1).values('name','count')
print(ret)
3 F和Q查询
# F查询:取出数据库的某个字段的值
# 把read_num都加1
from django.db.models import F
ret=models.Book.objects.all().update(read_num=F('read_num')+1)
print(ret)
#查询评论数大于阅读数的书籍
ret=models.Book.objects.all().filter(commit_num__gt=F('read_num'))
for i in ret:
print(i.name)
## 查询评论数大于阅读数2倍的书籍
ret=models.Book.objects.filter(commit_num__gt=F('read_num')*2)
print(ret)
# Q查询:制造 与或非的条件
# Q查询:制造 与或非的条件
# 查询名字叫egon或者价格大于100的书
from django.db.models import Q # Q是一个类
# ret=models.Book.objects.filter(Q(name='egon') | Q(price__gt=100)) |是或的条件
# 查询名字叫egon并且价格大于100的书
# ret=models.Book.objects.filter(Q(name='egon') & Q(price__gt=100)) &是与的条件,但是一般用下面这种
# ret=models.Book.objects.filter(name='egon',price__gt=100)
# 查询名字不为egon的书
# ret = models.Book.objects.filter(~Q(name='egon'))
# print(ret) ~是非的条件
# Q可以嵌套
ret = models.Book.objects.filter((Q(name='egon') & Q(price__lt=100)) | Q(id__lt=3))
print(ret)
4 原生sql
# 原生sql(有些sql用orm写不出来)
# 两种方案
# 第一种:用的比较少
# from django.db import connection
# cursor = connection.cursor()
# cursor.execute("""SELECT * from app01_book where id = %s""", [1])
# # row = cursor.fetchone()
# row = cursor.fetchall()
# print(row)
# 第二种,用的多
# books=models.Book.objects.raw('select * from app01_book where id >3')
# print(books) # RawQuerySet对象
# for book in books:
# print(book.name)
以下尽量不用
# books=models.Book.objects.raw('select * from app01_publish')
# for book in books:
# print(book.__dict__) # 动态语言,可以动态的添加东西因此导致了book表的对象取出的字段值不是原来book表的字段值,而变成了publish表中的值
# print(book.name)
# print(book.addr)
# print(book.email)
# print(book.price) # 能取出,但是相当于多进行了一次数据的查询
# authors = models.Author.objects.raw('SELECT app01_author.id,app01_author. NAME,app01_authordetail.sex FROM app01_author JOIN app01_authordetail ON app01_author.author_detail_id = app01_authordetail.id WHERE app01_authordetail.sex = 1') # rawqueryset中必须带主键
# for author in authors:
# print(author.name)
# print(author.__dict__)
5 defer和only
# defer和only(查询优化相关)
# only保持是book对象,但是只能使用only指定的字段,defer除了该字段;可以通过values取出咱们想要的字段,一旦用了values那么返回的是个字典对象,使用defer和only返回的是表的对象
# books = models.Book.objects.all().only('name')
# print(books[0].name)
# print(books[0].price) # 能出来,但是相当于再次进行了数据库的查询
# books = models.Book.objects.all().only('name')
# print(books[0].__dict__)
books = models.Book.objects.all().defer('name','price')
print(books[0].__dict__)
7 事务(请求,装饰器,局部)
# 事物:ACID,事物的隔离级别,锁, 行级锁,表级锁
# djanog orm中使用事物:原子性操作,要么都成功,要么都失败
# 新增一个作者详情,新增一个作者
# 事物的三个粒度
# 1 局部使用
from django.db import transaction
with transaction.atomic(): # 都在事物中,要么都成功,要么都失败
author_detail=models.AuthorDetail.objects.create(addr='xxx',phone='123',sex=1)
# raise Exception('抛了异常')
author=models.Author.objects.create(name='llqz',age=19,author_detail=author_detail)
# 2 视图函数装饰器,这一个视图函数都在一个事物中
# @transaction.atomic
# def index(request):
# return HttpResponse('ok')
# 3 整个http请求,在事物中,在setting.py中配置
'''
DATABASES = {
'default': {
...
'ATOMIC_REQUEST': True,
}
}
'ATOMIC_REQUEST': True,
设置为True统一个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。
'''