zoukankan      html  css  js  c++  java
  • orm查询优化, MVC与MTV, choices参数, ajax

    orm查询优化

    惰性查询, 目的: 减少不必要的数据库操作, 降低数据库的压力

    缓存数据库, redis, mongodb, 目的: 缓解主库压力, 相当于一个非常大的内存, 速度快同时也能做持久化

    能少走一次数据库就少走一次

    only与defer

    only:

    1. only括号内放字段, 查询结果是一个列表套数据对象
    2. "对象.括号内的字段"不会再查询数据库, 直接获取属性值
    3. "对象.括号内没有的字段"会查询数据库获取结果
        queryset = models.Book.objects.only('title')
    
        # 查询1次数据库: SELECT "..."."id", "..."."title" FROM "..." ...
        print(queryset)  # <QuerySet [<Book: Book object>, ...]>,
    
        for obj in queryset:  # 查询1次数据库: SELECT "..."."id", "..."."title" FROM "..." ...
            
            print(obj.title)  # 不查询数据库: 红楼梦, ...
    
            # 一共查询7次数据库: SELECT "..."."id", "..."."price" FROM "..." WHERE "..."."id" = 1; ...
            print(obj.price)  # 111.00, ...
    

    defer:

    1. defer与only互为反操作
    2. "对象.括号内的字段"会查询数据库获取结果
    3. "对象.括号内没有的字段"不会再查询数据库, 直接获取属性值
        queryset = models.Book.objects.defer('title')
    
        for obj in queryset:  # 查询1次数据库: SELECT "..."."id", "..."."price", "..."."publish_date", "..."."publish_id" FROM "...";
    
            # 一共查7次数据库: SELECT "..."."id", "..."."title" FROM "..." WHERE "..."."id" = 1;
            print(obj.title)  # 红楼梦, ...
    
            print(obj.price)  # 不查询数据库: 111.00, ...
    
    1. select_related括号内只能放外键字段,
    2. 并且外键字段只能是多对一或者一对一, 不能是多对多,
    3. 内部是自动联表操作, 会将括号中的外键字段所关联的表与当前表自动拼接成一张表,
    4. 然后将表中的一条条数据封装成一个个对象, 使跨表查询也不需要重复走数据库,
    5. 括号中可以放多个外键字段, 会将全部外键字段关联的表与当前表拼成一张大表
        queryset1 = models.Book.objects.all()
    
        # 查询1次数据库: SELECT "x"."id", "x"."title", "x"."price", "x"."publish_date", "x"."publish_id" FROM "x" ...
        print(queryset1)  # <QuerySet [<Book: Book object>, ...]>
    
        for obj in queryset1:  # 查询1次数据库: SELECT * FROM "app01_book" ...
    
            # 一共查询7次数据库: SELECT "app01_publish"."id", "y"."name", "y"."address" FROM "y" WHERE "y"."id" = 1; ...
            print(obj.publish.name)  # 如果改成: print(obj.title), 则不查询数据库
    
        queryset2 = models.Book.objects.select_related('publish')
    
        # 查1次数据库: SELECT "x".*, "x".* FROM "x" INNER JOIN "y" ON ("x"."publish_id" = "y"."id"); ...
        print(queryset2)  # <QuerySet [<Book: Book object>, ...]>
    
        for obj in queryset2:  # 查询1次数据库: SELECT "x".*, "x".* FROM "x" INNER JOIN "y" ON ("x"."publish_id" = "y"."id"); ...
            print(obj.title)  # 不查询数据库: 红楼梦, ...
            print(obj.publish.name)  # 不查询数据库: 东方出版社, ...
    
    1. 内部是子查询, 按步骤查询多张表, 然后将查询的结果封装到对象中, 给用户的感觉像是联表操作
    2. 括号中可以放多个外键字段(包括多对多关系), 每多放一个外键字段, 就会多走一条查询该外键字段关联表的sql语句
        queryset = models.Book.objects.prefetch_related('publish', 'author')
    
        '''
        查询3次数据库:
            1. SELECT "x"."id", "x"."title", "x"."price", "x"."publish_date", "x"."publish_id" FROM "x" ...
            2. SELECT "y"."id", "y"."name", "y"."address" FROM "y" WHERE "y"."id" IN (1, 2, ...); ...
            3. SELECT ..., "z".* FROM "z" INNER JOIN "w" ON ("z"."id" = "w"."author_id") WHERE "w"."book_id" IN (1, 2, ...); ...
        '''
        print(queryset)  # <QuerySet [<Book: Book object>, ...]>
    
        for obj1 in queryset:  # 查询3次数据库, sql语句同上
            print(obj1.publish.name)  # 不查询数据库: 东方出版社, ...
            
            # print(obj1.author.all().values_list('name'))  # <QuerySet [('jason',), ...]>, queryset对象获取字段值仍然会7次走数据库
            
            for obj2 in obj1.author.all():  
                print(obj1.title, obj2.name)  # 不查询数据库: 红楼梦 jason, ...
    

    小结

    selected_related: 耗时在数据库层面的联表操作上

    prefetch_related: 耗时在查询的次数上

    当两张表特别大时, selected_related花费时间可能更多

    MTV与MCV模型

    django自称为MTV框架, 本质还是MVC

    MTV:

    • M: models, 数据库模型表
    • T: templates, html模板
    • V: views, 视图层(FBV | CBV)

    MVC:

    • Model, 数据库模型
    • View: 处理数据的显示
    • Controller: 处理数据的交互

    choices参数

    一般用于性别, 学历等能完全列举出可能值的字段,

    例如: 数据在数据库中按数字存, 取的时候按照提前设定的对应关系转换成真正的数据

    migrations文件夹下必须要有一个__init__.py文件, 否则会报错: No changes detected

    # models.py
    class User(models.Model):
        ...
        gender_choice = (
            (1, '男'),
            (2, '女'),
            (3, '其他'),
        )
        gender = models.IntegerField(choices=gender_choice)
    
    
    #test.py
    user_obj1 = models.User.objects.get(pk=3)
    user_obj2 = models.User.objects.get(pk=10)
    print(user_obj1)  # User object
    
    print(user_obj1.get_gender_display())  # 其他
    print(user_obj2.get_gender_display())  # 4
    
    '''
    1. 包含choices参数的字段类型获取对应关系值的句式: get_字段名_display()
    2. 弱限制: 如果存储的数字不在提前设定的对应关系中, 能够正常存储, 也能够正常获取, 获取的结果为表中实际结果
    3. 对应关系中的第一个参数不一定是数字, 也可以是字符串
    '''
    

    ajax简介

    XML

    xml也是一门标记语言, 应用场景:

    • 写配置文件
    • 写前端页面
    • 应用于开发企业内部管理软件的框架odoo中
    • odoo框架内部功能实现全部依赖于python2, 其中薪资功能的实现最复杂

    AJAX

    最大的优点是在不重新加载整个页面的情况下, 可以与服务器交换数据并更新部分网页内容

    同步交互: 客户端发出一个请求后, 需要等待服务器响应结束后, 才能发出第二个请求

    异步交互: 客户端发出一个请求后, 无需等待服务器返回响应, 就能发出第二个请求

    '''
    # ajax POST请求发送普通键值对数据, 实现页面数据局部刷新
    1. 页面上有三个input框
    2. 前两个框输入数字, 并将输入的数字用post请求提交到后端, 最后一个框展示两数之和
    3. 要求页面不刷新
    
    
    def ajax(request):
        # print(request.is_ajax())  # 判断当前请求是否是ajax请求
        # print(request.POST)  # ajax发送的post请求, 普通的键值对也在request.POST中
    
        if request.is_ajax():
            d1 = request.POST.get('d1')
            d2 = request.POST.get('d2')
            res = int(d1) + int(d2)
            return HttpResponse(res)  # 结果返回给前端的异步回调函数, 一旦使用ajax请求, 数据只与回调函数交互
    
        return render(request, 'ajax.html')
        
        
    <script>
        $('#d4').on(
            'click', function () {
                // 开启ajax语法的句式:
                $.ajax({
                    url: '',  // 指定前端提交ajax POST请求到后端时使用的url, 和form表单中的action用法一样
                    type: 'post',  // 控制请求提交的方式, 不写默认提交get请求
                    data: {'d1': $('#d1').val(), 'd2': $('#d2').val()},  // 指定前端提交到后端的数据
                    success: function (data) {  // data为异步提交数据后, 后端返回给前端的对该数据的处理结果
                        $('#d3').val(data)  // 前端的回调函数处理后端的返回结果
                    }
                })
    
            }
        )
    </script>
    '''
    

    前后端数据交互的编码格式

    前端向后端发送请求的途径

    a标签的href参数: 只能发送GET请求

    form表单: 可以发送GET| POST请求, 但发送的POST请求数据不能是json格式

    ajax: 可以发送GET| POST请求, 发送的post请求数据默认编码格式为application/x-www-form-urlencoded

    GET请求数据拼接在url后面: url?x=a&y=b

    post请求数据的三种编码格式

    • application/x-www-form-urlencoded, multipart/form-data, application/json
    • 前端查看POST请求数据编码方式: f12-->Network-->Headers-->Request Headers-->Content-Type
    • 前端查看POST请求数据: f12-->Network-->Headers-->Form Data-->view source
    • django针对...-form-urlencoded编码格式的POST请求数据, 会自动解析并封装到request.POST中
    • django针对multipart/formdata编码格式的POST请求数据, 会将满足...-form-urlencoded编码格式的数据解析到request.POST中, 将文件数据解析到request.FILES中
    • 发送json格式数据只能借助ajax
    • 在涉及前后端交互时, 要做到数据的格式与数据的编码格式一致

    ajax POST请求发送json格式的数据

    '''
    <script>
        $('#d4').on(
            'click', function () {
                $.ajax({
                    url: '', 
                    type: 'post',  
                    contentType: 'application/json',  // 指定ajax POST请求数据的编码格式
                    data: JSON.stringify({'username': 'jason', 'password': '123'}),  // 前端数据使用JSON.stringify序列化为json格式
                    success: function (data) {  
                        alert(data.username)  
                    }
                })
            }
        )
    </script>
    
    
    def ajax(request):
        from django.http import JsonResponse
        import json
    
        if request.is_ajax():
            json_bin = request.body  # 获取json格式二进制数据
            json_str = json_bin.decode('utf8')  # 解码
            user_dic = json.loads(json_str)  # 反序列化
            return JsonResponse(user_dic)  # JsonResponse会自动将后端的字典转换成前端的object类型数据
    
        return render(request, 'ajax.html')
    '''
    

    ajax POST请求发送文件格式的数据

    ajax传文件需要借助JavaScript中的内置对象

    JavaScript实例化对象的关键字: new

    FormData类的对象既可以携带文件数据, 也支持携带普通的键值对

    '''
    <script>
        $('#d1').on(
            'click',
            function () {
                var myFormData = new FormData();  // 实例化得到myFormData对象
                myFormData.append('username', 'jason');  // 添加普通键值数据
                myFormData.append('girl_img', $('#d2')[0].files[0]);  // 获取input框中文件对象, 并添加到myFormData对象中
                $.ajax({
                    ...,
                    data: myFormData,  
                    contentType: false,  // 不使用myFormData对象内部自带的编码, 类似于json.dumps自动转码中文
                    processData: false,  // 设置浏览器不处理发送的数据
                    success: function (data) {
                        console.log($('#d2')[0].files);  // FileList {0: File, length: 1}
                        console.log($('#d2')[0].files[0]);  // File {name: "666.jpg", ..., size: 35122, type: "image/jpeg"  }
                        alert(data.username);
                    }
                })
            }
        )
    </script>
    
    
    def ajax(request):
        if request.is_ajax():
            print(request.POST)  # <QueryDict: {'username': ['jason']}>
            print(request.FILES)  # <MultiValueDict: {'girl_img': [<...: 666.jpg (image/jpeg)>]}>
    	...
    '''
    

    django内置的序列化模块

    序列化的目的: 将数据整合成一个大字典的形式, 使前后端分离之后能方便地进行数据交互

    def my_serialize(request):
        from django.core import serializers
    
        user_queryset = models.User.objects.all()
    
        res = serializers.serialize('json', user_queryset)  # json为要序列化成的数据格式
    	print(res, type(res))  # [{"model": "app01.user", "pk": 1, "fields": {"name": "nick", "gender": 1}}, ...] <class 'str'>
        
        return HttpResponse(res)
    
  • 相关阅读:
    NSIS制作安装程序
    poj_1011木棒
    hdoj_1312Red and Black
    搜索题目推荐及解题报告
    应届生就职前要读的几本书
    poj_1564Sum It Up
    priority_queue用法
    hdoj_2952Counting Sheep
    poj_1154LETTERS
    poj_2362
  • 原文地址:https://www.cnblogs.com/-406454833/p/11983979.html
Copyright © 2011-2022 走看看