ORM优化、事务、字段及Ajax
ORM查询优化
1.ORM的查询默认都是惰性处理
惰性处理:如果只是书写了orm语句,在后面根本没有用到该语句所查询出来的参数,那么orm会自动识别出来,直接不执行。
举例:res=models.Book.objects.all() # 这时orm是不会走数据库的
print(res) # 只有当要用到上述orm语句的结果时,才去数据库查询
2.ORM的查询自带分页处理
3.only与defer
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英语的意思就是只有,我们可以理解为通过only查询出来的对象内只会有小括号内的字段的值,如果想要获取其它字段的值,还得在查一次数据库或者说在执行一次SQL语句
'''
res = models.Book.objects.defer('title','price')
# print(res) # queryset [数据对象、数据对象]
for obj in res:
# print(obj.title) # 点击括号内填写的字段 走SQL查询
# print(obj.price)
print(obj.publish_time) # 点击括号内没有的字段获取数据 不走SQL查询
'''
defer刚好和only相反,defer小括号里写了啥,它反倒不给你,它会给你除了括号内的所有字段值。当你获取小括号内的字段值时,回去查询,获取不在小括号内的字段值时反倒不用去查询
'''
res = models.Book.objects.all()
for obj in res:
print(obj.publish.name) # 每次查询都走SQL
res = models.Book.objects.select_related('publish') # 先连表后查询封装
for obj in res:
print(obj.publish.name) # 不再走SQL查询
res1 = models.Author.objects.select_related('author_detail') #括号内不支持多对多字段,其它一对多和一对一支持
print(res1)
select_related括号内放外键字段,并且外键字段的类型只能是一对一和一对多,不能是多对多
内部自动做联表操作,会将括号内外键字段所关联的表与当前表自动拼接成一张表,然后将表中的数据一个个查询出来封装成一个个的对象,这样做就不会重复走数据库,减轻数据库压力。
select_related括号内可以放多个外键字段,用逗号隔开,会将多个外键字段关联的表拼接成一张大表
后续对象通过正反向查询跨表,内部不会走数据库查询
res = models.Book.objects.prefetch_related('publish') # 子查询
for obj in res:
print(obj.publish.name)
prefetch_related内部是子查询,会自动按照步骤查询多张表,然后将查询的结果封装到对象中,这样给用户的感觉还是链表操作。
括号内支持多个外键字段,并且没有类型限制,每放一个外键字段,就会多走一条SQL语句,多查询一次表。
'''
将多次查询之后的结果封装到数据对象中,后续对象通过正反向查询跨表,内部不会再走数据库查询
'''
ORM事务操作
django orm提供了至少三种开启事务的方式
方式1:settings.py配置文件数据库相关添加键值对 全局有效
"ATOMIC_REQUESTS": True每次请求所涉及到的orm操作同属于一个事务
方式2:装饰器 视图函数的局部有效
from django.db import transaction
@transaction.atomic
def index():pass
方式3:with上下文管理(视图函数里面的with上下文里面的才有效)
from django.db import transaction
def reg():
with transaction.atomic():
pass
ORM常用字段类型
AutoField
int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列.
CharField
字符类型,必须提供max_length参数, max_length表示字符长度.
IntegerField 整数
DecimalField(max_digits=None, decimal_places=None):可以指定精度的十进制浮点数
参数max_digits表示总位数
参数decimal_places表示小数位数
DateField[auto_now=False, auto_now_add=False]):日期
参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false,不人为修改不会改变
参数auto_now_add和auto_now是相互排斥的,组合将会发生错误
DateTimeField[auto_now=False, auto_now_add=False]):日期
参数auto_now表示每次保存对象时,自动设置该字段为当前时间,用于"最后一次修改"的时间戳,它总是使用当前日期,默认为false
参数auto_now_add表示当对象第一次被创建时自动设置当前时间,用于创建的时间戳,它总是使用当前日期,默认为false,不人为修改不会改变
参数auto_now_add和auto_now是相互排斥的,组合将会发生错误
BooleanField
传布尔值自动存0或1
TextField
存储大段文本
EmailField
存储邮箱格式数据
FileField
传文件对象 自动保存到提前配置好的路径下并存储该路径信息
ORM还支持用户自定义字段类型
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)
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其实质是利用浏览器提供的一个特殊的对象(XMLHttpRequest)异步地向服务器发送请求,服务器返回部分数据,浏览器让你去利用这些数据对象页面做部分的更新,整个过程,页面无刷新,不打断用户的操作。
同步和异步的区别
同步:如果与服务器端的交互方式是同步,当客户端与服务器交互时,客户端就不能进行其他操作,只能等待服务器端的响应,会刷新页面。
异步:当客户端正在进行正常操作时,还可以同时与服务器进行交互,服务器响应客户端信息,将信息更新到网页局部,整个过程页面不刷新。
'''
ajax不是一种新语言。它是几种技术的综合使用。
ajax是一种技术。
ajax是一种在WEB应用程序中向服务器发送异步请求,接收异步响应的技术。
特点:异步提交 局部刷新
我们所学习的是jQuery封装的版本 所以页面上必须要提前导入jQuery资源
'''
基本语法:
$.ajax({
url:'', //后端地址 三种填写方式,与form标签的action一致(当前页面,完整URL,指定URL路径)
type:'post', //请求方式,默认是get
data:{'v1':v1Val,'v2':v2Val}, //发送的数据
success:function (args) { //后端返回结果之后自动触发 args接收后端返回的数据
$('#d3').val(args)
}
})
ajax小案例
urls.py:
#ajax小案例
path('ab_ajax/',views.ajax_func,name='ajax_view'),
views.py:
def ajax_func(request):
if request.method == 'POST':
v1=request.POST.get('v1')
v2=request.POST.get('v2')
v3=int(v1)+int(v2)
return HttpResponse(v3)
return render(request,'ajaxPage.html')
ajaxPage.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
</head>
<body>
<input type="text" id="d1">+<input type="text" id="d2"> =<input type="text" id="d3">
<button id="suBtn">点我发送ajax请求</button>
<script>
//2.给按钮发送点击事件
$('#suBtn').click(function (){
//1.先获取两个框里的数据
let v1val=$('#d1').val();
let v2val=$('#d2').val();
//3.发送ajax请求
$.ajax({
url:'', //后端地址,不写给当前页面发送
type:'post', //请求方式,默认是get
data:{'v1':v1val,'v2':v2val}, //发送数据
success:function (args){ //后端返回结果之后自动触发 args接收后端返回的数据
$('#d3').val(args)
}
})
})
</script>
</body>
</html>
Content-Type
1.urlencoded
ajax默认的编码格式、form表单默认也是
数据格式 xxx=yyy&uuu=ooo&aaa=kkk
request.POST\request.GET
django后端会自动处理到request.POST中
2.formdata
django后端针对普通的键值对还是处理到request.POST中,但是针对文件会处理到request.FILES中
3.application/json
ps:表单不支持 ajax可以
urls.py:
#ajax小案例
path('ab_ajax/',views.ajax_func,name='ajax_view'),
views.py:
def ajax_func(request):
if request.method == 'POST':
print(request.body) # b'{"name":"jason","age":23}'
import json
res = json.loads(request.body)
print(res,type(res)) # {'name': 'jason', 'age': 23} <class 'dict'>
request.JSON = res
print(request.JSON) #
return render(request,'ajaxPage.html')
ajaxPage.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
</head>
<body>
<button id="btn">点击发送json数据</button>
<script>
$('#btn').click(function (){
$.ajax({
url:'',
type:'post',
data:JSON.stringify({'name':'jason','age':23}), //js的json反序列化(把数据转换成json)
contentType:'application/json',
success:function (args){
alert(args)
}
})
})
</script>
</body>
</html>
ajax携带文件数据
<input type="file" id="d2">
<button id="d3">携带文件数据</button>
<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>
后端:
def ajax_func(request):
if request.method == 'POST':
print(request.FILES)
#<MultiValueDict: {'file': [<InMemoryUploadedFile: locale.hpi (application/octet-stream)>]}>
print(request.POST)
#<QueryDict: {'name': ['jason'], 'age': ['18']}>
return render(request,'ajaxPage.html')
ajax补充说明
主要是针对回调函数args接收到的响应数据
1.后端request.is_ajax()
用于判断当前请求是否由ajax发出
2.后端返回的三板斧都会被args接收不再影响整个浏览器页面
3.选择使用ajax做前后端交互的时候 后端一般返回的都是字典数据
4.ajax自动反序列化后端的json格式的bytes类型数据
dataType:'json'
代码:
urls.py:
# ajax回调函数相关问题
path('ab_ajax/',views.ab_ajax_func)
views.py:
def ab_ajax_func(request):
if request.method == 'POST':
data = {'code':10000,'username':'jason','age':18}
#方式一
import json
user_data = json.dumps(data)
return HttpResponse(user_data)
# from django.http import JsonResponse
# return JsonResponse(data)
return render(request,'AjaxPage.html')
AjaxPage.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
</head>
<body>
<button id="d1">发送ajax请求</button>
<script>
$('#d1').click(function (){
$.ajax({
url:'',
type:'post',
data:{'name':'jason'},
dataType:'json',
success:function (args){
console.log(args);
console.log(typeof args)
console.log(args.username)
{#let userObj = JSON.parse(args);#}
{#console.log(userObj);#}
{#console.log(typeof userObj);#}
{#console.log(userObj.username)#}
}
})
})
</script>
</body>
</html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· AI Agent开发,如何调用三方的API Function,是通过提示词来发起调用的吗