• django之ORM的查询优化、Ajax 06


    ORM查询优化

    only与defer

    res = models.Book.objects.all().values('title')
    print(res) # <QuerySet [{'title': '三国演义'}, {'title': '红楼梦'}, {'title': '水浒传'}, {'title': '天龙八部'}]>
    for i in res:
    
        print(i,type(i))  # <class 'dict'>
        print(i.title)  # AttributeError: 'dict' object has no attribute 'title'  ,for循环出来就是第一个普通的字典,字典没有点取值的方式
    

    only:查询only后括号内指定的字段,查询一次,之后再点字段不会再查数据库了;如果点的是其他字段,会再次操作数据库;

    # 点指定字段
    res = models.Book.objects.only('title')
    print(res)  # 返回的是一个QuerySet对象,列表内是一个个类的对象;
    for i in res:
        print(i.title)
    

    # 点其他字段
    res = models.Book.objects.only('title')
    # print(res)
    for i in res:
        print(i.price)
    

    refer:refer和only互为反关系,按照refer指定字段查找,操作数据库一次,之后对象点指定的属
    性,每点一次,操作一次数据库;如果点其他字段,整体只操作一次数据库。

    
    # 点指定字段
       res = models.Book.objects.defer('title')
        # print(res)
        for i in res:
            print(i.title)
    

    # 点其他字段
    res = models.Book.objects.defer('title')
    # print(res)
    for i in res:
        print(i.price)
    

    select_related与prefetch_related查询优化

    select_related:括号内只能放外键字段,并且外键字段的类型只能是一对多,或者 一对一,不能是多对多;
    内部是自动连表操作,会将括号内外键字段所关联的表与当前表自动拼接成一张表,然后将表中的数据一个个查询出
    来封装成一个个的对象。这样做的好处就在于跨表也不需要重复的走数据库了,减轻数据库的压力。
    select_related括号内可以放多个外键字段,逗号隔开,会将多个外键字段关联的表与当前表全部拼成一张大表。

    res = models.Book.objects.select_related('publish')
    print(res)  # <QuerySet [<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]>
    
    for i in res:
        print(i.publish) # 只操作一次数据库
    	'''
    	Publish object
    	Publish object
    	Publish object
    	Publish object	
    	'''
    

    一对多的情况:

    res = models.Book.objects.select_related('publish')
    # print(res)
    for i in res:
        print(i.publish) # 只操作一次数据库
    

    一对一的情况:

    res = models.Author.objects.select_related('author_detail')
    # print(res)
    for i in res:
       print(i.author_detail) 
    
    # 内部做的也是联表操作,同一对多一样,也是内连接
    

    多对多的情况:

    res = models.Book.objects.select_related('author')
    # print(res)
    for i in res:
        print(i.author) 
    '''
    报错信息:
    django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'author'. Choices are: publish
    '''
    

    prefetch_related:内部是子查询,会自动帮你按步骤查询多张表 然后将查询的结果封装到对象中,
    给用户的感觉好像还是连表操作,括号内支持传多个外键字段 并且没有类型限制。
    特点:每放一个外键字段 就会多走一条sql语句 多查询一张表

    res = models.Book.objects.prefetch_related('publish','authors')
    # print(res)
    for i in res:
        print(i.publish,i.authors.all()) 
    '''
    Publish object <QuerySet [<Author: Author object>, <Author: Author object>]>
    Publish object <QuerySet []>
    Publish object <QuerySet []>
    Publish object <QuerySet []>
    '''
    

    两者之间的优缺点比较

    结合实际情况,看表的数据量的大小,
    两张表都特别大的情况下,连表操作可能耗时更多;
    

    choices参数

    choices字段类型,在获取值得时候统一的句式:get_字段名_display()

    1.建表

    # models.py文件
    
    from django.db import models
    # Create your models here.
    class User(models.Model):
        username = models.CharField(max_length=32)
        password = models.BigIntegerField()
        gender_choices = (
            (1,'男'),  # 第一个参数可以是数字,也可以是自定义的字符串
            (2,'女'),
            (3,'其他'),
        )
        gender = models.IntegerField(choices = gender_choices)
    

    2.数据库迁移命令 数据录入

    这里我们使用的是django自带的测试用的db.sqlite3数据库,并在表中添加数据

    菜单栏Tools>Run manage.py Task
    django 终端:1.makemigrations 2.migrate

    3.测试环境配置及示例分析

    from django.test import TestCase
    
    # Create your tests here.
    
    import os
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day56.settings")
        import django
        django.setup()
        
        from app01 import models
    
        user_obj1 = models.User.objects.get(pk = 1)
        user_obj2 = models.User.objects.get(pk = 4)
        # print(user_obj1.gender) # 1
        # print(user_obj2.gender) # 4  这里id=4并没有gender对应的性别关系,但不报错。
        print(user_obj1.get_gender_display()) # 男    正确的获取方式
    	  print(user_obj2.get_gender_display())  # 4  没有性别的对应关系获取到的还是数字本身
    

    choices参数在实际项目中的表设计

    MTV与MVC模型

    MTV模型:

    django就是MTV框架,但本质还是MVC

    MTV:
    M:models
    T:templates
    V:views

    MVC:
    M:models
    V:views
    C:controller 路由匹配

    MVVM :前端框架,比如:Vue

    Ajax简介

    AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。
    即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。

    AJAX 不是新的编程语言,而是一种使用现有标准的新方法。

    AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网
    页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)

    AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。

    • 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
    • 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。

    了解:

    XML也是一门标记语言
    该语法应用场景
        1.写配置文件
        2.可以写前端页面(odoo框架中  erp)
    每家公司都会有属于这家公司独有的内部管理软件
    专门用来开发企业内部管理软件 框架  odoo
    odoo框架内部功能实现全部依赖于python2
    

    AJAX常见应用情景

    1)搜索引擎根据用户输入的关键字,自动提示检索关键字。
    2)还有一个很重要的应用场景就是注册时候的用户名的查重。

    其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服
    务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。

    • 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
    • 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!

    当输入用户名后,把光标移动到其他表单项上时,浏览器会使用AJAX技术向服务器发出请求,服务器会
    查询名为lemontree7777777的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户
    已经存在了,浏览器在得到结果后显示“用户名已被注册!”。

    • 整个过程中页面没有刷新,只是局部刷新了;
    • 在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;

    AJAX的优缺点

    优点:
    - AJAX请求无须刷新整个页面;
    - 两个关键点:1.局部刷新,2.异步请求
    - AJAX使用JavaScript技术向服务器发送异步请求;
    - 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;

    Ajax基本语法结构

    $.ajax({ })

    // ajax基本语法结构
    $.ajax({
    url:'',  // 数据提交的后端地址  不写就是往当前页面提交  也可以写后缀 也可以写全称  跟actions一样
    type:'post',  // 提交方式  默认是get请求
    data:{'i1':$('#d1').val(),'i2':$('#d2').val()},  // 提交的数据
    success:function (data) {  // 形参data,就是异步提交之后后端返回的结果,两个data不是同一个
    $('#d3').val(data)  // 回调机制需要做的事情
    }
    })
    
    // 注意:使用ajax django三板斧都不再作用与页面 而是与data交互
    

    Ajax基本示例1(实现前后端数据交互)

    # urls.py文件
    # Ajax在post发送post请求的时候记得注销掉settings.py文件中的中间件
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^about_ajax/',views.xxx),
    ]
    
    # views文件
    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    
    def xxx(request):
        # print(request.is_ajax())  # 判断当前请求是否是Ajax请求,返回布尔值
        # print(request.POST)  # ajax发送的post请求,普通的键值对也在request.POST中获取
        # if request.method == 'POST':
        if request.is_ajax(): # True
            i1 = request.POST.get('i1')  # 默认取列表的最后一个元素,
            i2 = request.POST.get('i2')
            # print(i1,type(i1))  # 字符串类型  1 <class 'str'>
            res = int(i1) + int(i2)
            return HttpResponse(res)  # 把结果给异步回调函数success
    
        return render(request, 'xxx.html')
    
    // 这里直接使用JQuery封装好的方法,就不再用原生的js版本了。
    // xxx.html 文件
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    
    </head>
    <body>
    <input type="text" id="d1"> + <input type="text" id="d2"> = <input type="text" id = "d3">
    <button id="d4" style="color:orange">点我发送请求</button>
    
    <script>
        $('#d4').on('click',function () {
            $.ajax({
                url:'',
                type:'post',
                data:{'i1':$('#d1').val(),'i2':$('#d2').val()}, // 提交数据   data对应的是个字典,里面是键值对
                success:function (data) {  // 形参data就是异步提交之后后端返回的结果
                    {#alert(data)#}
                    $('#d3').val(data)  // 后端返回的结果就是这里的data接收的
                }
            })
        })
    </script>
    </body>
    </html>
    

    前后端传输数据编码格式

    前后端交互是一个数据编码格式,针对不同的数据,后端会进行不同的处理。
    一般请求:
    request.POST
    
    文件格式的请求:
    request.FILES
    

    发送请求三种编码格式:
    1.urlencoded
    2.formdata # form表单往后端发文件指定的编码格式
    3.application/json # Ajax往后端发送文件指定的编码格式

    能朝后端发数据的请求有哪些

    a标签href参数               get请求
    form表单					    get/post
    ajax                                get/post
    
    get请求的数据格式比较单一,这里不做研究。
    url?xxx=ooo&yyy=zzz
    

    form表单编码格式及发送文件(发post请求)

    第一种编码格式:urlencoded

    1).默认是urlencoded编码
    	Content-Type: application/x-www-form-urlencoded
    urlencoded所对应的数据格式:
    	username=zhang&password=123
    	
    django后端针对urlencoded编码格式的数据 会自动解析并且帮你封装到request.POST中
    

    第二种编码格式:multipart/form-data

    2). form表单指定enctype="multipart/form-data",
    	Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryhjKCHQHDmcE62iMQ
    	
    针对formdata格式的数据 你在浏览器上是无法查看到
    如果是一个文件对象,django后端也会自动识别,放到request.FILES中
    

    form表单在multipart/form-data编码格式下发送文件

    当form表单不指定参数enctype="multipart/form-data"时发生的情况:

    代码示例:

    from django.shortcuts import render,HttpResponse
    def about_form(request):
        if request.method=='POST':
            print(request.POST)  # <QueryDict: {'username': ['zhang'], 'password': ['123']}>
    
            print(request.FILES)  # <MultiValueDict: {'myfile': [<InMemoryUploadedFile: ORM查询优化.md (application/octet-stream)>]}>
    
        return render(request,'about_form.html')
    '''
    当about_form.html文件中form标签参数不指定enctype="multipart/form-data"时,后端打印结果为:
    <QueryDict: {'username': ['zhang'], 'password': ['123'], 'myfile': ['ORM查询优化.md']}>
    
    <MultiValueDict: {}>  无法拿到文件对象
    '''
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
        <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    
    </head>
    <body>
    <form action="" method="post" enctype="multipart/form-data">
        username:<input type="text" name="username">
        password:<input type="text" name="password">
        <input type="file" name="myfile">
        <input type="submit">
    </form>
    </body>
    </html>
    
    3).form表单无法发送json格式的数据,只能借助于ajax
    

    ajax传输数据的编码格式及发送文件(post请求)

    ajax发送
    1.urlencoded
    2.application/json post请求下前端发送json格式数据
    3.formdata

    第一种编码格式:默认的urlencoded编码格式

    1).Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    ajax默认的编码格式也是urlencoded,也就意味着后端django也是将数据解析到request.POST中
    


    在涉及到前后端交互的时候 一定要做到数据的格式与编码格式一致

    第二种编码格式:html文件中添加contentType参数为application/json,往后端发json格式数据

    2).django后端针对application/json编码格式的数据,不会做任何处理,数据怎么来的,只会原封不动的放到request.body中
    
    前端js 后端json
    stringify dumps
    parse loads

    第三种编码格式:multipart/form-data

     数据传到后端直接分成两个部分,数据信息放在POST中,文件放在FILES中
    

    Ajax发送json格式数据

    代码示例:

    # views.py 文件
    
    from django.shortcuts import render,HttpResponse
    def about_form(request):
        if request.method=='POST':
            print(request.body)  # b'{"username":"zhang","passowrd":"123"}'
            json_bytes = request.body
            import json
            # 方式1:
            # user_dic = json.loads(json_bytes.decode('utf8'))
            # print(user_dic)  # {'username': 'zhang', 'passowrd': '123'}
            # 方式2:
            user_dic = json.loads(json_bytes)  # 自动帮你解码家反序列化
            print(user_dic,type(user_dic))  # {'username': 'zhang', 'passowrd': '123'} <class 'dict'>
    
        return render(request,'about_form.html')
    
    
    <!--about_form.html文件-->
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    </head>
    <body>
    <button id="d1">点我发送json格式数据</button>
    <script>
        $('#d1').click(function () {
            $.ajax({
                url:'',
                type:'post',
                contentType:'application/json',  // 不写默认编码格式为urlencoded,form表单enctype指定编码格式
                data:JSON.stringify({'username':'zhang','passowrd':'123'}),
                success:function (data) {
                    alert(123)
                }
            })
        })
    </script>
    </body>
    </html>
    

    Ajax发送文件格式数据

    借助于内置对象new,该对象即可以携带文件数据,同样也支持普通的键值对
    代码示例:

    from django.shortcuts import render,HttpResponse
    
    def about_form(request):
        if request.method=='POST':
            # 数据传到后端直接分成两个部分,分别放在POST中,和FILES中
            print(request.POST)  # <QueryDict: {'username': ['zhang'], 'password': ['123']}>
            print(request.FILES)  # <MultiValueDict: {'myfile': [<InMemoryUploadedFile: ORM查询优化.md (application/octet-stream)>]}>
    
        return render(request,'about_form.html')
    
    <!--about_form.html文件-->
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    </head>
    <body>
    username:<input type="text">
    password:<input type="password">
    myfile:<input type="file" id="d1" name="myfile">
    <button id="d2">点我发送文件</button>
    <script>
        $('#d2').click(function () {
    				// 先生成一个内置对象
    				var MyFormData = new FormData();
    				// 1. 先添加普通的键值
    				MyFormData.append('username','zhang');  // 添加了一组普通的键值对
    				MyFormData.append('password','123');
    				// 2. 添加文件数据
    				MyFormData.append('myfile',$('#d1')[0].files[0]);  // 如何获取input框中文件对象$('#d1')[0].files[0]
    				$.ajax({
    					url:'',
    					type:'post',
    					data:MyFormData,
    					// 发送文件必须要指定的两个参数
    					contentType:false,  // 不使用任何编码  MyFormData对象内部自带编码 django后端能够识别  
    					processData:false,  // 不要处理数据  
    					success:function (data) {
    
    					}
    
    				})
    

    序列化

    序列化目的:将数据整合成一个大字典形式,方便前后端数据的交互,实现方便前后端分离。

    代码示例:

    from app01 import models
    from django.core import serializers
        
    def back_dict_in_list(request):
        user_queryset = models.User.objects.all()
       #  [{username:...,password:...,hobby:...,},{},{},{}]
       #  user_list = []
       #  for data in user_queryset:
        # 数据量比较大的情况下书写麻烦
       #      user_list.append(
       #          {'username':data.username,
       #           'password':data.password,
       #           'gender':data.get_gender_display(),
       #
       #           }
       #      )
        user_list = serializers.serialize('json', user_queryset)  # 能指定序列化到前端的数据格式
        return HttpResponse(user_list)
    

    本次内容总结点我
    django07:sweetalert、bulk_create批量插入、分页器

  • 相关阅读:
    Gradle中使用SpringBoot插件构建多模块遇到的问题
    使用docker-compose快速构建集群示例(一)
    tensorflow对多维tensor按照指定索引重排序
    tensorflow Dataset及TFRecord一些要点【持续更新】
    RNN、LSTM介绍以及梯度消失问题讲解
    使用BERT模型生成句子序列向量
    给定数字N,输出小于10^N的所有整数
    使用BERT模型生成token级向量
    使用BERT预训练模型+微调进行文本分类
    tensorflow与神经网络中遇到的问题与解决方法【持续更新】
  • 原文地址:https://www.cnblogs.com/zhangchaocoming/p/11965667.html
Copyright © 2020-2023  润新知