聚合查询
聚合函数:max、min、sum、avg、count
1.使用聚合函数之前需要导入模块
from django.db.models import Max, Min, Sum, Avg, Count
2.聚合函数的使用
聚合函数通常情况下是配合分组一起使用的
3.关键字aggregate
没有分组之前如果单纯的使用聚合函数 需要关键字aggregate
# 1.查询所有书的平均价格
res = models.Book.objects.aggregate(Avg('price'))
print(res) # {'price__avg': Decimal('183.117778')}
res1 = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk'))
print(res1)
分组查询
打开MySQL
输入>>>:show variables like '%mode%';
分组有一个特性 默认只能够直接获取分组的字段 其他字段需要使用方法
我们也可以忽略掉该特性 将sql_mode中only_full_group_by配置移除即可
1.分组查询
annotate()为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数,所有使用前要从django.db.models引入Avg,Max,Count,Sum(首字母大写))。
2.返回值
分组后,用values取值,则返回值是QuerySet书籍类型里面为一个个字典
分组后,用values_list取值,则返回值是QuerySet数据类型里面为一个个元组
MySQl中的limit相当于ORM中的QuerySet数据类型的切片
3.分组查询关键字
annotate() 里面放聚合函数
1.values 或者 values_list 放在 annotate 前面:values 或者 values_list 是声明以什么字段分组,annotate 执行分组。
2.values 或者 values_list 放在annotate后面: annotate 表示直接以当前表的pk执行分组,values 或者 values_list 表示查询哪些字段, 并且要将 annotate 里的聚合函数起别名,在 values 或者 values_list 里写其别名。
3.filter放在 annotate 前面:表示where条件
4.filter放在annotate后面:表示having
跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询
分组练习题
models后面点什么 就按什么分组
author_num 是我们自己定义的字段 用来存储统计出来的每本书对应的作者个数
1.统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('author__pk')).values('title', 'author_num')
print(res)
res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num')
print(res1)
"""
1.按照整条数据分组
models.Book.objects.annotate() 按照一条条书籍记录分组
2.按照表中某个字段分组()
models.Book.objects.values('title').annotate() 按照annotate之前values括号中指定的字段分组
"""
2.统计每个出版社卖的最便宜的书的价格
res1 = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
print(res1)
3.统计不止一个作者的图书
'''filter在annotate前面则是where 在annotate后面则是having'''
res = models.Book.objects.annotate(author_num=Count('author__pk')).filter(author_num__gt=1).values('title', 'author_num')
print(res)
4.查询各个作者出的书的总价格
res = models.Author.objects.annotate(book_sum_price=Sum('book__price')).values('name', 'book_sum_price')
print(res)
F与Q查询
导入模块
from django.db.models import F,Q
F查询
能够帮助你直接获取到列表中某个字段对应的数据
注意:
在操作字符串类型的数据的时候 F不能够直接做到字符串的拼接
当表中已经有数据的情况下 添加新的字段需要指定一些参数
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=2)
publish_time = models.DateTimeField(auto_now=True)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
author = models.ManyToManyField(to='Author')
'''
当表中已经有数据的情况下 添加新的字段需要指定一些参数
1.设置字段值存于为空 null=True
2.设置字段默认值 default=1000
3.在终端直接给出默认值
'''
storage_num = models.IntegerField(verbose_name='库存数', null=True)
sale_num = models.IntegerField(verbose_name='卖出数目', default=1000)
def __str__(self):
return f'对象:{self.title}'
1.查询卖出书大于库存数的书籍
res = models.Book.objects.filter(storage_num__gt = F('sale_num'))
print(res)
将所有书籍的价格上涨1000块
res = models.Book.objects.update(price=F('price') + 1000)
给所有书籍名称后面加上爆款后缀
*针对字符串数据无法直接拼接*
models.Book.objects.filter().all().update(title=F('title') + '爆款') # 针对字符串数据无法直接拼接
# 导入Concat模块
from django.db.models.functions import Concat
# 导入Value模块
from django.db.models import Value
models.Book.objects.filter().all().update(title=Concat(F('title'), Value('~爆款')))
Q查询
可以改变filter括号内多个条件之间的逻辑运算符,还可以将查询的结果改为字符串形式
filter() 等方法中的关键字参数查询都是一起进行"and",如果你需要执行更复杂的查询(例如ORM语句),你可以使用Q对象。
查询卖出数大于100并且价格小于60的书籍
res = models.Book.objects.filter(Q(sale_num__gt = 100), Q(price__lt = 600))
print(res)
查询卖出数大于130或者价格小于30的书籍
res = models.Book.objects.filter(Q(sale_num__gt = 130) | Q(price__lt = 30))
print(res)
查询卖出数不是大于80或者价格大于600的书籍
res = models.Book.objects.filter(~Q(sale_num__gt = 80) | Q(price__gt = 600))
print(res)
, and关系
| or关系
~ not关系
Q 默认是and,可以进行修改
q = Q()
q.connector = 'or'
Q查询的进阶用法
可以将查询的结果改为字符串形式
from django.db.models import Q
q_obj = Q() # 1.产生q的对象
q_obj.connector = 'or' # 默认多个条件的连接是and可以修改为or
q_obj.children.append(('pk', 1)) # 2.添加查询条件
q_obj.children.append(('price__gt', 2000)) # 支持添加多个
res = models.Book.objects.filter(q_obj) # 查询支持直接填写q对象
print(res)
ORM查询优化
django orm默认都是惰性查询
当orm的语句在后续的代码中 真正需要使用的时候才会执行
django orm自带limit分页
减轻数据库端以及服务端的压力
1.ORM查询优化之only(单表)
res = models.Book.objects.only('title', 'price')
print(res) # queryset [数据对象、数据对象]
for obj in res:
print(obj.title) # 点击括号内填写的字段 不走SQL查询
print(obj.price)
print(obj.publish_time) # 可以点击括号内没有的字段获取数据 但是会走SQL查询
"""
only会将括号内填写的字段封装成一个个数据对象 对象在点击的时候不会再走数据库查询
但是对象也可以点击括号内没有的字段 只不过每次都会走数据库查询
如果看到有人只有only查询的话 尽量不要去点括号内没有的字段 因为它每次都会去查询一次
"""
2.ORM查询优化之defer(单表)
res = models.Book.objects.defer('title', 'price')
print(res) # [数据对象, 数据对象]
for obj in res:
print(obj.title) # 点击括号内填写的字段 走SQL查询
print(obj.title)
print(obj.price)
print(obj.publish_time) # 可以点击括号内没有的字段获取数据 不会走SQL查询
"""
defer与only刚好相反
数据对象点击括号内出现的字段 每次都会走数据库查询
数据对象点击括号内没有的字典 不会走数据库查询
"""
3.ORM查询优化之select_related(多表)
res = models.Book.objects.all()
for obj in res:
print(obj.publish.name) # 每次查询都走数据库
res = models.Book.objects.select_related('authors') # 先连表后查询封装
"""
select_related括号内只接收外键字段(一对一 一对多) 它会在内部自动拼表 得出的数据对象在点击表中数据的时候都不会再走数据库查询
"""
4.ORM查询优化之prefetch_related
for obj in res:
print(obj.publish.name)
"""
prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的
"""
res = models.Book.objects.prefetch_related('publish') # 子查询
for obj in res:
print(obj.publish.name)
ORM事务操作
复习:
1.事务的四大特性
A: 原子性
每个事务都是不可分割的最小单位(同一个事物内的多个操作要么同时成功要么同时失败)
C: 一致性
事物必须是使数据库从一个一致性状态编导另一个一致性状态,一致性与原子性使密切相关的
I: 隔离性
事物与事物之间彼此不干扰
D: 持久性
一个事物一旦开启,它对数据库中书籍的改变就应该使永久性的
2.开始事务
开启事务:transaction
回滚:rollback
确认:commit
3.开启事务
django orm提供了至少三种开启事务的方式
方式1:配置文件数据库相关添加键值对 全局有效
"ATOMIC_REQUESTS": True每次请求所涉及到的orm操作同属于一个事务
方式2:装饰器 局部有效
from django.db import transaction
@transaction.atomic
def index():pass
方式3:with上下文管理 局部有效
from django.db import transaction
def reg():
with transaction.atomic():
pass
ORM常用字段类型
1.AutoField(int自增列)
int自增列,必须填入参数primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
2.CharField(varchar)
verbose_name:字段的注释
max_length:字符长度
3.IntegerField(int)
一个整数类型, -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
4.BigIntegerField(bigint)
5.DecimalField(decimal)
max_digits=8:总共位数
decimal_places=2:小数位
6.EmailFiled(varchar(254))
7.DateField(date)
日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
8.DateTimeField(datetime)
日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
auto_now:每次修改数据的时候都会自动更新当前时间
auto_now_add:只在创建数据的时候记录创建时间后续不会自动修改了
9.BooleanField(Field)(布尔值类型)
该字段传布尔值(False/True) 数据库里面存0/1
10.TextField(Field)(文本类型)
该字段可以用来存大段内容(文章、博客...) 没有字数限制
后面的bbs作业 文章字段用的就是TextField
11.FileField(Field)(字符类型)
upload_to = "/data"
给该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中
/data/a.txt
12.ForeignKey()()外键
13.OneToOneField()(一对一关系)
14.ManyToManyField()(多对多关系)
ORM还支持自定义字段类型
# 定义char类型
# 字段类内部都继承Field
class MyCharField(models.Field):
# 字符类型都必须有max_length表示字符长度
def __init__(self,max_length, *args, **kwargs):
self.max_length = max_length
# 调用父类的init方法
super().__init__(max_length=max_length, *args, **kwargs) # 一定要是关键字的形式传入
def db_type(self, connection):
# 返回真真正的数据类型及各种约束条件
return 'char(%s)' % self.max_length
# 自定义字段使用
myfield = MyCharField(max_length=16,null=True) # 可以为空
ORM常用字段参数
AutoField(Field)
- int自增列,必须填入参数 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必须填入参数 primary_key=True
注:当model中如果没有自增列,则自动会创建一个列名为id的列
from django.db import models
class UserInfo(models.Model):
# 自动创建一个列名为id的且为自增的整数列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定义自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整数 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整数 0 ~ 32767
IntegerField(Field)
- 整数列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整数 0 ~ 2147483647
BigIntegerField(IntegerField):
- 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field)
- 布尔值类型
NullBooleanField(Field):
- 可以为空的布尔值
CharField(Field)
- 字符类型
- 必须提供max_length参数, max_length表示字符长度
TextField(Field)
- 文本类型
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制
IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
GenericIPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
- 参数:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启此功能,需要protocol="both"
URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
FilePathField(Field)
- 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
- 参数:
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
width_field=None, 上传图片的高度保存的数据库字段名(字符串)
height_field=None 上传图片的宽度保存的数据库字段名(字符串)
DateTimeField(DateField)
- 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 时间格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
FloatField(Field)
- 浮点型
DecimalField(Field)
- 10进制小数
- 参数:
max_digits,小数总长度
decimal_places,小数位长度
BinaryField(Field)
- 二进制类型
ORM字段参数
# 外键字段及参数
unique=True
ForeignKey(unique=True) 等价于 OneToOneField()
db_index
如果db_index=True 则代表着为此字段设置索引
复习索引是什么?
答: 加快查询速度
to_field
设置要关联的表的字段 默认不写关联的就是另外一张的主键字段
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。
"""
django2.X及以上版本 需要你自己指定外键字段的级联更新级联删除
"""
字段参数
null
用于表示某个字段可以为空。
unique
如果设置为unique=True 则该字段在此表中必须是唯一的 。
db_index
如果db_index=True 则代表着为此字段设置索引。
default
为该字段设置默认值。
DateField和DateTimeField
auto_now_add
配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。
auto_now
配置上auto_now=True,每次更新数据记录的时候会更新该字段。
关系字段
ForeignKey
外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。
ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。
字段参数
to
设置要关联的表
to_field
设置要关联的表的字段
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。
models.CASCADE
删除关联数据,与之关联也删除
db_constraint
是否在数据库中创建外键约束,默认为True。
models相关:
1、models.CASCADE
级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
2、models.SET_NULL
当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
3、models.PROTECT
当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
4、models.SET_DEFAULT
当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
5、models.SET()
当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
6、models.DO_NOTHING
什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
其余字段参数
复制代码
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id",
on_delete=models.SET(func)
)
复制代码
OneToOneField
一对一字段。
通常一对一字段用来扩展已有字段。(通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联)
字段参数
to
设置要关联的表。
to_field
设置要关联的字段。
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。(参考上面的例子)
Ajax
我们知道,前端页面想要和后端进行数据交互,可以通过以下方式
将参数添加到url中,后端通过get方式从url中获取数据 GET请求
前端页面通过form表单,将数据以get或者post的方式发送给后端 POST请求/GET请求
前端通过a标签(和使用url方式参数的方式) GET请求
1.什么是Ajax
1.AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
2.Ajax不是新的编程语言,而是一种使用现有标准的新方法。其实就是js自带的功能 我们学习的是jQuery封装之后版本
2.Ajax的优点
1.Ajax最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
2.Ajax不需要任何浏览器插件,但需要用户允许javaScript在浏览器上执行。
同步交互: 客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求。
异步交互: 客户端发出一个请求后,无需要等待服务器响应结束,就可以发出第二个请求。
Ajax用于"局部刷新页面"和"异步提交"的特点
异步提交: 提交完认为不需要原地等待,立马就做其他事
局部刷新: 不在局限于整个页面的刷新,而是在于局部的某一个页面的小块刷新
因此和使用Form表单和后端进行数据交互的方式比较,具有以下优点:
1.Ajax使用JavaScript技术向服务器发送异步请求
2.Ajax请求无须刷新整个页面
因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以Ajax性能高!
3.Ajax工作原理
1.Ajax相当于在用户和服务器之间加了一个中间层(Ajax引擎),使用户操作与服务器响应异步化。
2.并不是所有用户请求都是提交给服务器,像一些数据验证和数据处理等都交给Ajax引擎自己来做,只有确定需要从服务器读取数据时再由Ajax引擎代为向服务器提交请求。
3.客户端发送请求,请求交给Ajax,Ajax把请求提交给服务器,服务器进行业务处理,服务器响应数据交给Ajax对象,Ajax对象接收数据,由JavaScript把数据写到页面上。
要完整实现一个Ajax异步调用和局部刷新,同窗需要以下几个步骤:
1.创建XMLHttpRequest对象,既创建一个异步调用对象
2.创建一个新的HTTP请求,并指定该HTTP请求的方法,URL及验证信息
3.设置响应HTTP请求状态变化的函数
4.发送HTTP请求
5.获取异步调用返回数据
6.使用JavaSciript和DOM实现局部刷新
注意:
Ajax传输数据为XML(当然,传输数据不只是XML,现在更多使用json数据,基本上web页面都是Ajax)
4.基本语法
$.ajax({
// 发送地址 1.不写默认朝当前所在url提交数据
// 2.全写 指名道姓 https://www.baidu.com
// 3.只写后缀/login/
url: '',
type: 'get/post', // 请求方式 默认get
data: {'username':'jason', 'password':123} // 要发送的数据
success:function(args){
// 回调函数(异步回调机制)
}
})
解析(重要):
1.当你在利用ajax进行前后端交互的时候
2.当后端给你返回结果的时候会自动触发 args接受后端的返回结果
小练习
<body>
<form action="" method="post">
<input type="text" id="d1">+ <input type="text" id="d2">= <input type="text" id="d3">
<input type="button" value="计算" id="subBtn">
<script>
$('#subBtn').click(function (){
// 超后端发送数据 使用ajax
$.ajax({
url:'', // 等价于form表单的action参数
type:'post', //等价于form表单的method参数
data:{'i1':$('#d1').val(),'i2':$('#d2').val()}, //要发送后端的数据
success:function (args){ // args就是异步提交以后,后端返回的结果
$('#d3').val(args)
}
})
})
</script>
</form>
</body>
def abAjax(request):
if request.method == 'POST':
i1 = request.POST.get('i1')
i2 = request.POST.get('i2')
res = int(i1) + int(i2)
return HttpResponse(res)
return render(request, 'abAjax.html')
5.数据编码格式
Content-Type:它会提前告诉后端,接下来的数据到底是什么格式,它会识别到不同的类型分配到不同的编码中
格式1:urlencoded
数据格式: name=jason&pwd=123&hobby=read
django后端统一处理到request.POST中
格式2:formdata
数据格式: 无法查阅
django后端自动将文件数据处理到request.FILES 普通数据request.POST
格式3:application/json
数据格式: json格式
django后端不会处理 在request.body中存储(bytes类型) 自己处理
语法注意事项
data: JSON.stringify({'name':'jason','pwd':123}),
contentType:'application/json',
向django发送请求以后,所携带的数据它会放在request.body中,然后识别是什么编码
如果是urlencoded编码,它会将数据解码给request.POST
如果是formdata那么它会解码以后交给request.FILES
那么现在的数据是JSON格式,争对JSON格式没有一个编码进行比对,所以没人管它
那么只能自己处理,
print(request.body)
json_bytes = request.body
import json
json_bytes = json.loads(json_bytes)
print(json_bytes)
"""
b'{"name":"jason","pwd":123}'
{'name': 'jason', 'pwd': 123}
"""
6.Ajax携带数据
$('#d3').click(function () {
// 1.产生内置对象
let formData = new FormData();
// 2.添加普通数据
formData.append('username',$('#d1').val())
// 3.添加文件数据
formData.append('file', $('#d2')[0].files[0])
// 4.发送ajax请求
$.ajax({
url:'',
type:'post',
data:formData,
contentType:false, // 不使用任何编码
processData:false, // 不处理数据对象
success:function (args) {
}
})
})
标签:models,res,price,Django7,查询,Ajax,print
From: https://www.cnblogs.com/zjl248/p/16993127.html