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)

image

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)

image

ORM查询优化

  1. ORM的查询默认都是惰性查询

    res = models.Book.objects.only('title','price').all()
    print('123')  # 按照以往的经验代码走到之这里上面的肯定就执行完毕了
    

    image

  2. ORM的查询自带分页处理

    res = models.Book.objects.only('title','price').all()
    print('123')  # 按照以往的经验代码走到之这里上面的肯定就执行完毕了
    print(res)
    

    image

  3. only与defer

only

数据对象+含有指定字段对应的数据

点括号内存在的字段

res = models.Book.objects.only('title','price')
print(res)  # 这里如果放在for循环queryset上面打印就会先查一下数据分页处理,然后下面for循环查的时候直接查完,不在分页
for obj in res:
    print(obj.price)  # 点上面填写的字段时候只会查一次数据库

image

不会每次查询

点括号内不存在的字段

res = models.Book.objects.only('title','price')
for obj in res:
    print(obj.publish)  # 点括号内不存的字段时候,每点一次,就查询一次sql语句

image

会每次查询

defer

点括号内存在的字段

res = models.Book.objects.defer('title','price')
for obj in res:
    print(obj.title)  # 点括你有的字段,每点一次查询一次

image

点括号内不存的字段

res_query = models.Book.objects.defer('title','price')
for obj in res_query:
    print(obj.pk)  # 点括号内不存在的字段,只查询一次

image

点击外键字段在括号内

res_query = models.Book.objects.defer('title','price','publish')
for obj in res_query:

    print(obj.publish)  # 在点击外键时候,外键在括号内,查询次数根据子查询在查一遍,相当于元数据的一倍

image

点击外键字段不在括号内

res_query = models.Book.objects.defer('title','price')
for obj in res_query:
    print(obj.publish) # 点外键不在括号内时,只查询数据个数次数

image

only与defer小总结:

使用only时,点的字段在括号内,就只查询一次SQL语句,点的字段不在括号内,就会每次查询都走SQL语句

使用defer时,点的字段在括号内,每次查询都走SQL语句,点的字段不在括号内,就只走一次SQL语句

不能放多对多字段

res_query = models.Book.objects.select_related('authors')  # 只能放外键字段,并且不能放多对多字段
print(res_query)

image

先连表后查询封装

res_query = models.Book.objects.select_related('publish')  # 括号内只能使用一对对外键和者,一对一外键
for obj in res_query:
    print(obj.publish.name)  # 底层使用的连表操作,执行走一次SQL语句

image

res_query = models.Book.objects.prefetch_related('authors') # 括号内所有外键都可使用
for obj in res_query: # 底层使用的是子查询操作
    print(obj.authors.all())  #查询字段值按照ORM跨表查询
    print(obj.title)

image

ORM事务操作

  1. 事务的四大特性(ACID)

    原子性
    一致性
    隔离性
    持久性

  2. 相关SQL关键字
    start transactions;
    roll back;
    commit;
    save point;

  3. 相关重要概念
    脏读,不可重复读,幻读,mvcc多版本控制、

再没有开启事务时,只要执行sql成功,下面错误不影响上面sql语句

def transcation(request):
    models.Publsh.objects.create(name='哈哈哈',address='1231')
    print('执行SQL完毕')
    asdasdasdas
    return HttpResponse('123')

image

django orm提供了至少三种开启事务的方式

方式1:配置文件数据相关添加键值对 全局有效

'ATOMIC_REQUESTS': True,  # 每次请求所涉及到的ORM操作为一个事务
    
    
def transcation(request):
    models.Publsh.objects.create(name='撒旦胡卡',address='123')
    print('执行SQL完毕')
    asdasdasdas
    return HttpResponse('123')

image

只要再一个视图函数中或者视图类中的一个请求中,都同属一个事务,只要出现错误就回滚到之前的状态

方式2:装饰 局部有效

@transaction.atomic  #局部有效
def transcation(request):
    models.Publsh.objects.create(name='撒旦胡卡', address='123')
    print('执行SQL完毕')
    asdasdasdas
    return HttpResponse('123')

image

方式3:上下文管理 局部有效

def ttt(request):
    print(123)
    with transaction.atomic():
        models.Publsh.objects.create(name='撒旦胡卡', address='123')
        print('执行SQL完毕')
        asdasdasdas
        return HttpResponse('123')

image

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接收到的响应数据

  1. 后端request.is_ajax()
    用于判断当前请求是否是ajax发出

  2. 后端返回的三板斧都会把args接收不在影响整个浏览器页面

  3. 选择使用ajax做前后端交互的时候 后端一般返回的都是字典数据

    user_dict={'code':10000,'username':'张三','age':29}
    

ajax自动反序列化后端的json格式的bytes类型数据

dataType:'json',

image

posted @ 2022-12-19 19:51  clever-cat  阅读(36)  评论(0编辑  收藏  举报