django ORM查询优化,事务,ajax,ORM常用关键字
ORM查询优化,事务,ajax
内容概要
- Q查询进阶操作
- ORM查询优化
- ORM事务操作
- ORM常用字段类型
- ORM常用字段参数
- ORM三种创建多对多的方式
- Ajax请求
内容详细
Q查询进阶操作,默认and连接
from django.db.models import Q
q_obj = Q()
# q_obj.connector = 'or'
q_obj.children.append(('pk', 1)) # 默认连接符是and
q_obj.children.append(('publish_id',1))
res = models.Book.objects.filter(q_obj)
print(res)
from django.db.models import Q
q_obj = Q()
q_obj.connector = 'or' # 修改连接符 为or
q_obj.children.append(('publish__gt', 2))
q_obj.children.append(('title__contains','三国'))#支持添加多个
res = models.Book.objects.filter(q_obj) # 查询对象支持填写Q对象
print(res)
ORM查询优化
-
ORM的查询默认都是惰性查询
res = models.Book.objects.only('title','price').all() print('123') # 按照以往的经验代码走到之这里上面的肯定就执行完毕了
-
ORM的查询自带分页处理
res = models.Book.objects.only('title','price').all() print('123') # 按照以往的经验代码走到之这里上面的肯定就执行完毕了 print(res)
-
only与defer
only
数据对象+含有指定字段对应的数据
点括号内存在的字段
res = models.Book.objects.only('title','price')
print(res) # 这里如果放在for循环queryset上面打印就会先查一下数据分页处理,然后下面for循环查的时候直接查完,不在分页
for obj in res:
print(obj.price) # 点上面填写的字段时候只会查一次数据库
不会每次查询
点括号内不存在的字段
res = models.Book.objects.only('title','price')
for obj in res:
print(obj.publish) # 点括号内不存的字段时候,每点一次,就查询一次sql语句
会每次查询
defer
点括号内存在的字段
res = models.Book.objects.defer('title','price')
for obj in res:
print(obj.title) # 点括你有的字段,每点一次查询一次
点括号内不存的字段
res_query = models.Book.objects.defer('title','price')
for obj in res_query:
print(obj.pk) # 点括号内不存在的字段,只查询一次
点击外键字段在括号内
res_query = models.Book.objects.defer('title','price','publish')
for obj in res_query:
print(obj.publish) # 在点击外键时候,外键在括号内,查询次数根据子查询在查一遍,相当于元数据的一倍
点击外键字段不在括号内
res_query = models.Book.objects.defer('title','price')
for obj in res_query:
print(obj.publish) # 点外键不在括号内时,只查询数据个数次数
only与defer小总结:
使用only时,点的字段在括号内,就只查询一次SQL语句,点的字段不在括号内,就会每次查询都走SQL语句
使用defer时,点的字段在括号内,每次查询都走SQL语句,点的字段不在括号内,就只走一次SQL语句
select_related与prefetch_related
select_related
不能放多对多字段
res_query = models.Book.objects.select_related('authors') # 只能放外键字段,并且不能放多对多字段
print(res_query)
先连表后查询封装
res_query = models.Book.objects.select_related('publish') # 括号内只能使用一对对外键和者,一对一外键
for obj in res_query:
print(obj.publish.name) # 底层使用的连表操作,执行走一次SQL语句
prefetch_related
res_query = models.Book.objects.prefetch_related('authors') # 括号内所有外键都可使用
for obj in res_query: # 底层使用的是子查询操作
print(obj.authors.all()) #查询字段值按照ORM跨表查询
print(obj.title)
ORM事务操作
-
事务的四大特性(ACID)
原子性
一致性
隔离性
持久性 -
相关SQL关键字
start transactions;
roll back;
commit;
save point; -
相关重要概念
脏读,不可重复读,幻读,mvcc多版本控制、
再没有开启事务时,只要执行sql成功,下面错误不影响上面sql语句
def transcation(request):
models.Publsh.objects.create(name='哈哈哈',address='1231')
print('执行SQL完毕')
asdasdasdas
return HttpResponse('123')
django orm提供了至少三种开启事务的方式
方式1:配置文件数据相关添加键值对 全局有效
'ATOMIC_REQUESTS': True, # 每次请求所涉及到的ORM操作为一个事务
def transcation(request):
models.Publsh.objects.create(name='撒旦胡卡',address='123')
print('执行SQL完毕')
asdasdasdas
return HttpResponse('123')
只要再一个视图函数中或者视图类中的一个请求中,都同属一个事务,只要出现错误就回滚到之前的状态
方式2:装饰 局部有效
@transaction.atomic #局部有效
def transcation(request):
models.Publsh.objects.create(name='撒旦胡卡', address='123')
print('执行SQL完毕')
asdasdasdas
return HttpResponse('123')
方式3:上下文管理 局部有效
def ttt(request):
print(123)
with transaction.atomic():
models.Publsh.objects.create(name='撒旦胡卡', address='123')
print('执行SQL完毕')
asdasdasdas
return HttpResponse('123')
ORM常用字段类型
class Test1(models.Model):
id = models.AutoField(primary_key=True) # 主键字段 int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
var1 = models.CharField(max_length=32) # 字符串字段,必须指定max_length 字符类型,必须提供max_length参数, max_length表示字符长度。
var2 = models.IntegerField() # 整数字段最大11位 一个整数类型,范围在 -2147483648 to 2147483647。(一般不用它来存手机号(位数也不够),直接用字符串存,)
var3 = models.BigIntegerField() # 大整数字段
var4 = models.DecimalField(max_digits=8, decimal_places=2) # 小数字段
var5 = models.DateTimeField(auto_now_add=True) # 年月日时分秒,时间字段
var6 = models.DateField(auto_now=True) # 年月日,时间字段
var7 = models.BooleanField() # 布尔字段 传布尔值自动存0或1
var8 = models.TextField() # 存储大段文本 无需传入max_length参数
var9 = models.EmailField() # 储存邮件格式数据
var10 = models.FileField() # 传文件对象 自动保存到提前配置好的路径下并存储好该路径信息
FileField(Field)
- 字符串,路径保存在数据库,文件上传到指定目录
- 参数:
upload_to = "" 上传文件的保存路径
storage = None 存储组件,默认django.core.files.storage.FileSystemStorage
ORM还支持用户自定义字段类型
class MyCharField(models.Field):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
def db_type(self, connection):
return 'char(%s)' % self.max_length
class Usera(models.Model):
name = models.CharField(max_length=32)
info = MyCharField(max_length=10)
ORM常用字段参数
primary_key 主键
verbose_name 注释
max_length 字段长度
max_digits 小数总共多少位
decimal_places 小数点后面的位数
auto_now 每次操作数据自动更新事件
auto_now_add 首次创建自动更新事件后续不自动更新
null 允许字段为空
default 字段默认值
unique 唯一值
db_index 给字段添加索引
choices 当某个字段的可能性能够被列举完全的情况下使用
性别、学历、工作状态、...
class User(models.Model):
name = models.CharField(max_length=32)
info = MyCharField(max_length=64)
# 提前列举好对应关系
gender_choice = (
(1, '男性'),
(2, '女性'),
(3, '其他'),
)
gender = models.IntegerField(choices=gender_choice,null=True)
user_obj = User.objects.filter(pk=1).first()
user_obj.gender
user_obj.get_gender_display()
to 关联表
to_field 关联字段(不写默认关联数据主键)
on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。
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相似
Ajax
异步提交 局部刷新
ajax不是一门新的技术并且有很多版本 我们目前学习的是jQuery版本(版本无所谓 本质一样就可以)
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
基本语法
<P><input type="text" id="input1">+<input type="text" id="input2">=<input type="text" id="input3"></P>
<input type="submit" id="sub">
<script>
let sub = $('#sub').click(function () {
var in1 = $('#input1').val()
var in2 = $('#input2').val()
console.log(in1,in2)
$.ajax({
url:'', <!--后端地址 三种填写方式 与form标签action一致-->
type:'post', // 请求方式 默认也是get
data:{'var1':in1,'var2':in2}, //发送的数据
success:function (args) { //后端返回结果之后自动触发 args接收后端返回的数据
$('#input3').val(arg)
}
})
})
</script>
Content-Type
urlencoded
ajax默认的编码格式、form表单默认也是
数据格式 xxx=yyy&zzz=bbb&aaa=ccc
django后端会自动处理到request.POST中
formdata
django后端针对普通的键值对还是处理到request.POST中
但是针对文件会处理到request.FILES中
application/json
form表单不支持 ajax可以
<script>
$('#d1').click(function () {
$.ajax({
url:'',
type:'post',
data:JSON.stringify({'name':'jason','age':18}), // 千万不要骗人家
contentType:'application/json',
success:function (args) {
alert(args)
}
})
})
</script>
后端需要从request.body中获取并自己处理
ajax携带文件数据
<script>
$('#d3').click(function () {
// 1.先产生一个FormData对象
let myFormDataObj = new FormData();
// 2.往该对象中添加普通数据
myFormDataObj.append('name', 'jason');
myFormDataObj.append('age', 18);
// 3.往该对象中添加文件数据
myFormDataObj.append('file', $('#d2')[0].files[0])
// 4.发送ajax请求
$.ajax({
url:'',
type:'post',
data:myFormDataObj,
// ajax发送文件固定的两个配置
contentType:false,
processData:false,
success:function (args){
alert(args)
}
})
})
</script>
后端还是从request.FILES中获取文件
Ajax补充说明
主要是针对回调函数args接收到的响应数据
-
后端request.is_ajax()
用于判断当前请求是否是ajax发出 -
后端返回的三板斧都会把args接收不在影响整个浏览器页面
-
选择使用ajax做前后端交互的时候 后端一般返回的都是字典数据
user_dict={'code':10000,'username':'张三','age':29}
ajax自动反序列化后端的json格式的bytes类型数据
dataType:'json',