(3)Q查询进阶操作
研究查询条件的左边是什么? 字段名还是变量名?
models.Book.objects.filter(pk=1)
发现是变量名
如果想让左边不是变量名而是字段名,则需要用到Q查询
Q:还可改变条件左侧变量名改为字段名,目的是将来更好的跟用户交互
比如在前端页面有个搜索框,让用户输入按什么条件搜索数据,传入到后端的数据都是字符串,就可以用该字符串去做筛选
案例:查询id是1或价格大于1000的书名
from django.db.models import Q
q_obj=Q()# 产生Q对象
q_obj.connector='or' #默认多个条件的连接时and可以改为or
q_obj.children.append(('pk',1))#添加查询条件
q_obj.children.append(('price_gt',1000))#支持添加第二个查询条件
res=models.Book.objects.filter(q_obj)# 查询支持直接填写q对象
print(res)
使用q_obj.connector='or'
可从默认and
关系改为or
关系
from django.db.models import Q
# 1.由于Q是一个类,类名加括号可以产生一个对象
q_obj = Q()
# 多个查询条件改为or关系
q_obj.connector = 'or'
# 2.往q对象中添加查询条件
q_obj.children.append(('pk', 1))
# 可以添加第二个条件(可添加多个)
q_obj.children.append(('price__gt', 1000))
# 查询支持直接填写q对象
res = models.Book.objects.filter(q_obj)
print(res)
13)ORM四个查询优化(面试)
(1)惰性查询
ORM的查询默认都是惰性查询
。目的是为了节省效率
res = models.Book.objcets.all()
# 不执行 除非真正需要使用才会执行 如:print(res)
(2)自带分页处理
ORM的查询自带分页处理
。目的是为了减轻数据库及服务端的压力
res=models.Book.objects.all()
print(res)
#当要查询book表中所有数据时,如果表中有几亿条数据一下全找出来电脑会承受不住,所以查看底层sql发现会自动做分页LIMIT处理,每次拿的数据都不多
(3)only与defer
主要适用于单表操作
①only
作用:可以将括号里列举的字段封装到数据对象中。当点括号里的字段时不会走SQL查询,但是一但点括号里没有的字段则会每点一次走一次数据库查询
。
缺点:一但数据特别多时,点括号里没有的字段,会走多次SQL查询,电脑会扛不住
res = models.Book.objects.only('title','price')
# print(res) # queryset [数据对象、数据对象]
for obj in res:
# print(obj.title) # 点括号内的字段 不走SQL查询
print(obj.publish_time) # 点括号里没有的字段 走SQL查询
②defer
与only相反
作用:可以将括号里列举的字段封装到数据对象中。当点括号里没有的字段时不会走SQL查询,但是一但点括号里有的字段则会每点一次走一次数据库查询
缺点:一但数据特别多时,点括号里有的字段,会走多次SQL查询,电脑会扛不住
res = models.Book.objects.defer('title','price')
# print(res) # queryset [数据对象、数据对象]
for obj in res:
# print(obj.publish_time) # 点括号里没有的字段 不走SQL查询
print(obj.title) # 点括号内的字段 走SQL查询
(4)select_related与prefetch_related
主要适用于多表操作
res = models.Book.objects.all()
for obj in res:
print(obj.publish.name) # 每次跨表查询都会走SQL语句
①select_related
注:括号里不能写多对多外键字段,一对一、一对多都可以
作用:可以提前把表里的数据封装好。当跨表查询点字段时不会走SQL查询
res=models.Book.objects.select_related('publish') # 先连表后查询封装
for obj in res:
print(obj.publish.name) # 不走sql查询语句
②prefetch_related
与select_related区别在于不仅是封装,还会查询(多一步)。其实用的时候都差不多感觉不出来!
作用:先执行一条SQL,把一条SQL的结果当作另一条SQL的条件去查询。
res = models.Book.objects.prefetch_related('publish') # 子查询
for obj in res:
print(obj.publish.name)
14)ORM事物操作
# 复习事物
1.事务的四大特性(ACID)
原子性、一致性、隔离性、持久性
2.相关SQL关键字
start transaction # 开启事物操作
rollback # 可回退到修改操作前的状态
commit # 提交确认事物
savepoint # 节点 类似存档,结合回退用,回退到该节点
3.四种隔离级别
1.read uncommitted(未提交读)
事务中的修改即便没提交,对其他事物也都是可见的。事物可以读取未提交的数据,这一现象也叫'脏读'。
【'脏读'】简单理解为开启事物修改数据后没有提交确认时,又有另一个事物来获取数据,获取到的就是内存里的数据而不是本应该在硬盘里的真实数据。
2.read committed(提交读 或 不可重复读) # 大多数据库默认隔离级别
一个事物从开始一直到提交之前所作的任何修改对其他事务都是不可见的,也叫'不可重复读'
简单理解就是开启事物修改数据后没有提交确认时,又有另一个事物来获取数据,获取到的是修改前硬盘里的数据。
3.repeatable read(可重复度) # MySQL默认隔离级别
能够解决'脏读'问题,但无法解决'幻读'问题
【'幻读'】简单理解为当某个事物在读取某个范围内的记录时,另一个事物又在该范围内插入了新记录,当之前的事物再次读取该范围的记录会产生'幻行'。
【'幻行'】简单理解为假如事物1对一个表中的5条数据做查询3条记录操作,同时事物2过来把其中的1条数据删掉了,事物1就只能查询2条。
InnoDB和XtraDB通过'多版本并发控制'(MVCC)及'间隙锁策略'可以解决幻读的问题。
4.serializable(可串行读)
强制多个事物串行执行(排队执行)。由于效率太低所以很少用。
django orm提供了至少三种开启事务的方式:
每种都可以 全局有效更方便,局部可扩展性更高
方式1:配置文件【数据库相关】添加键值对 #全局有效
"ATOMIC_REQUESTS": True 每次请求所涉及到的orm操作同属于一个事务,只要有一个报错则全部回滚。'如果没配置事物,有一个orm报错则上一个执行成功不会回滚。'
方式2:装饰器 #局部有效
from django.db import transaction
@transaction.atomic # 被该装饰器修饰的视图函数下同属于一个事物
def index(request):
pass
return HttpResponse('xxx')
方式3:with上下文管理 #局部有效
from django.db import transaction
def reg(request):
with transaction.atomic(): # 视图函数中的with下同属一个事物
pass
return HttpResponse('xxx')
15)ORM常用字段类型
AutoField() #自定义属性
-primary_key=True
CharField() #字符类型
-max_length()
IntegerField() #整型
BigIntergerField() #大整型
DecimalField()
-max_digits()#小数总长度
-decimal_places()#小数位长度
DateField() #日期
-auto_now
-auto_now_add
DateTimeField() #日期时间
-auto_now
-auto_now_add
BooleanField() #传布尔值自动存0或1
TextField() #存储大段文本
EmailField() #邮箱格式
FileField() #传文件对象,自动保存到指定路径,并存路径信息
自定义字段
class MyCharField(models.Field):
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super().__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
return 'char(%s)' % self.max_length
class User(models.Model):
name = models.CharField(max_length=32)
info = MyCharField(max_length=64)
16)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 #当删除关联表中的数据时,当前表与其关联的行的行为。
-models.CASCADE
级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除
-models.SET_NULL
当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空
-models.PROTECT
当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除
-models.SET_DEFAULT
当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值
-models.SET()
当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数
-models.DO_NOTHING
什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
14.组件
1)Ajax组件
异步提交,局部刷新
简单理解就是:注册页面,当输入注册名字时不点提交按钮
后端自动校验
,并把校验结果返回到页面且不影响其他内容的填写。要想实现以上情况则必须要用Ajax来实现
(1)Ajax简介
Ajax(Asynchronous Javascript And XML)翻译成中文就是"异步的Javascript和XML".即使用Javascript语言与服务器进行异步交互,传输的数据为XML。
Ajax不是新的编程语言
,而是一种实现现有标准的新方法。
Ajax最大的优点就是:不重新加载整个页面的情况下与服务器交互部分网页内容
。(让用户不知不觉中完成请求和响应)。
Ajax有多个版本,以下使用jQuery封装后的版本。本质一样都是异步提交,局部刷新
,只是参数不同。
(2)基本语法
$.ajax({
// 数据提交地址 与action一致
url:'',
// 请求方式 默认get(小写) 与method一致
type:'post',
// 要发送的数据
data:{'v1':v1Val, 'v2':v2Val},
// 后端返回结果之后自动触发 args接收后端返回的数据(异步回调函数)
success:function (args) {
$('#d3').val(args)
}
})
'异步回调函数:只要我朝你发数据,你给我响应了就会自动触发function函数的执行'
练习:做三个input框 ,第一个框加第二个框点击一个按钮把消息发到后端计算,结果返回到第三个框中。要求不能用JS,页面不能刷新。
#【urls.py】
path('ab_ajax/', views.ab_ajax_func),
————————————————————————————————————————————————
#【views.py】
def ab_ajax_func(request):
if request.method == 'POST':
# print(request.POST) # <QueryDict: {'v1': ['1'], 'v2': ['2']}>
v1 = request.POST.get('v1')
v2 = request.POST.get('v2')
# print(v1,v2) # 1 2
res = int(v1) + int(v2)
return HttpResponse(res)
# 后端views.py中的三板斧不再影响页面,而是交给args形参
# return HttpResponse('123')
# return render(request,'ab_ajax.html')
# return redirect('https://www.baidu.com')
return render(request, 'ab_ajax.html')
——————————————————————————————————————————————————
#【ab_ajax.html】
<body>
<input type="text" id="d1"> +
<input type="text" id="d2"> =
<input type="text" id="d3">
<button id="subBtn">点击发送ajax请求</button>
<script>
// 1.给按钮绑定点击事件
$('#subBtn').click(function(){
// 2.获取前两个框里的数据
let v1Val = $('#d1').val();
let v2Val = $('#d2').val();
// 3.发送ajax请求
$.ajax({
url:'',
type:'post',
data:{'v1':v1Val,'v2':v2Val},
success:function (args){
$('#d3').val(args)
}
})
})
</script>
</body>
练习升级:把按钮取消掉,给第二个框换成失去焦点事件,当失去焦点后自动发送ajax请求
//给第二个标签绑定失去焦点事件
$('#d2').blur(function(){
(3)Content-Type(数据的编码格式)
①urlencoded
ajax、form表单默认的编码格式
数据格式: xxx=yyy&uuu=ooo&aaa=kkk
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中获取并自己处理
(4)ajx携带文件数据
<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>
标签:obj,框架,models,res,查询,ajax,django,数据
From: https://www.cnblogs.com/lvqingmei/p/16993445.html