Q查询进阶操作
这里主要就是让查询数据的时候,可以使用input
获取的信息,进行用户交互
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查询优化
- ORM的查询默认都是惰性查询
- ORM的查询自带分页处理
- only与defer
准备工作:
settings.py
添加该配置参数:
# 只要操作数据库那么就会打印sql语句 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
惰性查询特点
如果只是书写了orm
语句,在后面根本没有用到该语句所查询出来的参数,那么orm
会自动识别出来,直接不执行
例如:
res = models.Book.objects.all() # 这时orm是不会走数据库的 print(res) # 只有当要用到的上述orm语句的结果时,才回去数据库查询
前置说明
这里需要做一些具体的说明,方便大家理解only和defer
当我们在Django
中执行ORM操作进行数据库查询的时候,其实内部的代码把所有的数据库中的记录,都封装到了ORM
操作的对象中去了,因此我们可以通过点的方式或是索引等方式查询到对应的数据。
但是当遇到查询的时候需要查询不在条件中的记录时,就需要执行sql
语句进行查询了。
比如我们在查询的时候,需要的结果在外键对应的表中,这时候去外键对应的表中查询数据,就需要执行sql
语句进行查询,并且查询一条记录需要执行一次sql
语句
而我们的only
的作用是把写在括号内的参数中的字段的值封装到对象中,让后续查找的时候 不需要执行sql
语句进行查询,加快执行速度。或是起到一个减少代码封装的数据量,加快运行的作用。
而defer
则是和only
相反,写在括号内的字段值不会被封装到对象中,别的字段反而会被封装到对象中
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查询
defer用法
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查询
select_related联表操作
# 跟跨表操作有关 示例: # 查询每本书的出版社名字 res = models.Book.objects.all() for i in res: print(i.publish.name) # 使用all方法查询的时候,每一个对象都会去数据库查询数据
# 使用select_related() res = models.Book.objects.select_related() for i in res: print(i.publish.name) # 直走一次数据库 INNER JOIN链表操作 """ select_related内部直接先将book与publish连起来 然后一次性将大表里面的所有数据 全部封装给查询出来的对象 这个时候对象无论是点击book表的数据还是publish的数据都无需再走数据库查询了 select_related括号内只能放外键字段 一对多 一对一 多对多也不行 """ # 这样就比all方法更加的优化一点,这样网络请求就少了,延迟就降低了,提高效率。
prefetch_related子查询
# 跟跨表操作有关 res = models.Book.objects.prefetch_related('publish') # 子查询 for i in res: print(i.publish.name) """ prefetch_related该方法内部其实就是子查询 将子查询查询出来的所有结果也给你封装到对象中 给你的感觉好像也是一次性搞定的 """
总结:
# prefetch_related对比select_related少了一次查询 # 到底孰优孰劣呢? 各有优缺点:如果表特别特别大的时候使用prefetch_related品表阶段就要耗费很长的时间,而select_related子查询虽然查询两次,但是操作两个表的时间非常短效率就会胜于联表查询prefetch_related
ORM事务操作
""" 1.事务的四大特性(ACID) 原子性、一致性、隔离性、持久性 2.相关SQL关键字 start transaction; rollback; commit; savepoint; 3.相关重要概念 脏读、幻读、不可重复读、MVCC多版本控制... """ 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常用字段类型
AutoField 主键字段 primary_key=True CharField varchar verbose_name 字段的注释 max_length 长度 IntegerField int BigIntegerField bigint 应用场景:电话号码的存取 DecimalField 浮点类型 max_digits=8 长度 decimal_places=2 小数位数 EmailFiled varchar(254) DateField date DateTimeField datetime auto_now:每次修改数据的时候都会自动更新当前时间 auto_now_add:只在创建数据的时候记录创建时间后续不会自动修改了 BooleanField(Field) - 布尔值类型 该字段传布尔值(False/True) 数据库里面存0/1 应用场景:数据是否删除 TextField(Field) - 文本类型 该字段可以用来存大段内容(文章、博客...) 没有字数限制 后面的bbs作业 文章字段用的就是TextField FileField(Field) - 字符类型 upload_to = "/data" 给该字段传一个文件对象,会自动将文件保存到/data目录下然后将文件路径保存到数据库中 /data/a.txt
ORM自定义字段类型
class MyCharField(models.Field): def __init__(self,max_length,*args,**kwargs): self.max_length = max_length # 调用父类的init方法 # 一定要是关键字的形式传入 super().__init__(max_length=max_length,*args,**kwargs) super() 函数是用于调用父类(超类)的一个方法。 super() 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。 MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。 上述的super是调用__init__方法,传入的方式以关键字的形式进行传入是因为括号当中的参数第一个是verbose_name,如果不按照关键子参数进行传递,第一个参数就变成传递给verbose_name def db_type(self, connection): """ 返回真正的数据类型及各种约束条件 :param connection: :return: """ return 'char(%s)'%self.max_length
自定义字段使用
myfield = MyCharField(max_length=16,null=True) # 外键字段及参数 # unique相当于是OneToOne unique=True ForeignKey(unique=True) === OneToOneField() # 你在用前面字段创建一对一 orm会有一个提示信息 orm推荐你使用后者但是前者也能用 db_index 如果db_index=True 则代表着为此字段设置索引 to_field 设置要关联的表的字段 默认不写关联的就是另外一张的主键字段 on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。 django2.X及以上版本 需要你自己指定外键字段的级联更新级联删除
ORM常用字段参数
名称 | 含义 |
---|---|
primary_key | 主键 |
verbose_name | 注释 |
max_length | 字段长度 |
max_digits | 小数总共多少位 |
decimal_places | 小数点后面的位数 |
auto_now | 每次操作数据自动更新事件 |
auto_now_add | 首次创建自动更新事件后续不自动更新 |
null | 允许字段为空 |
default | 字段默认值 |
unique | 唯一值 |
db_index | 给字段添加索引 |
choices | 当某个字段的可能性能够被列举完全的情况下使用。如:性别、学历、工作状态、... |
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简介
Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指⼀种创建交互式网页应⽤的网页开发技术。 Ajax 是⼀种⽤于创建快速动态网页的技术。 Ajax 是⼀种在⽆需重新加载整个网页的情况下,能够更新部分网页的技术。 通过在后台与服务器进⾏少量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进⾏更新。 传统的网页(不使⽤ Ajax)如果需要更新内容,必须重载整个网页页面
同步与异步
-
同步:发送⼀个请求,需要等待响应返回,然后才能够发送下⼀个请求,如果该请求没有响应,不能发送下⼀个请求,客户端会处于⼀直等待过程中
-
异步:发送⼀个请求,不需要等待响应返回,随时可以再发送下⼀个请求,即不需要等待
注意:ajax不是一门新的技术并且有很多版本 我们目前学习的是jQuery版本(版本无所谓 本质一样就可以)
Ajax工作原理
-
搜索引擎根据用户输入的关键字,自动提示检索关键字。
-
还有一个很重要的应用场景就是注册时候的用户名的查重。
-
其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。
-
整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
AJAX的优点
- AJAX使用JavaScript技术向服务器发送异步请求;
- AJAX请求无须刷新整个页面;
- 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
- 两个关键点:
1.局部刷新
2.异步请求
基本语法
$.ajax({ url:'', // 后端地址 三种填写方式 与form标签的action一致 type:'post', // 请求方式 默认也是get data:{'v1':v1Val, 'v2':v2Val}, // 发送的数据 success:function (args) { // 后端返回结果之后自动触发 args接收后端返回的数据 $('#d3').val(args) } })
jQuery发送AJAX请求示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> .hide { display: none; } </style> </head> <body> <p><input type="text" class="user"><span class="hide" style="color: red">用户名已存在</span></p> <script src="/static/jquery-3.3.1.min.js"></script> {#下面这一项是基于jQuery的基础上自动给我们的每一个ajax绑定一个请求头信息,类似于form表单提交post数据必须要有的csrf_token一样#} {#否则我的Django中间件里面的校验csrf_token那一项会认为你这个请求不是合法的,阻止你的请求#} <script src="/static/setup_Ajax.js"></script> <script> //给input框绑定一个失去焦点的事件 $('.user').blur(function () { //$.ajax为固定用法,表示启用ajax $.ajax({ //url后面跟的是你这个ajax提交数据的路径,向谁提交,不写就是向当前路径提交 url:'', //type为标定你这个ajax请求的方法 type:'POST', //data后面跟的就是你提交给后端的数据 data:{'username':$(this).val()}, //success为回调函数,参数data即后端给你返回的数据 success:function (data) { ret=JSON.parse(data); if (ret['flag']){ $('p>span').removeClass('hide'); } } }) }); </script> </body> </html>
数据编码格式(Content-Type)
1.urlencoded ajax默认的编码格式、form表单默认也是 数据格式 xxx=yyy&uuu=ooo&aaa=kkk django后端会自动处理到request.POST中 2.formdata django后端针对普通的键值对还是处理到request.POST中 但是针对文件会处理到request.FILES中 3.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携带文件数据
html <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> views def ab_ajax_func(request): if request.method == 'POST': print(request.POST) print(request.FILES) 这里就可以看到文件的数据了 return render(request, 'abAjaxPage.html')