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後括號內指定的字段,查詢一次,以後再點字段不會再查數據庫了;若是點的是其餘字段,會再次操做數據庫;html

# 點指定字段
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括號內能夠放多個外鍵字段,逗號隔開,會將多個外鍵字段關聯的表與當前表所有拼成一張大表。python

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  
    '''

一對多的狀況:jquery

res = models.Book.objects.select_related('publish')
# print(res)
for i in res:
    print(i.publish) # 只操做一次數據庫

一對一的狀況:ajax

res = models.Author.objects.select_related('author_detail')
# print(res)
for i in res:
   print(i.author_detail) 

# 內部作的也是聯表操做,同一對多同樣,也是內鏈接

多對多的狀況:sql

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 []>
'''

二者之間的優缺點比較django

結合實際狀況,看錶的數據量的大小,
兩張表都特別大的狀況下,連表操做可能耗時更多;

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=jason&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批量插入、分頁器

相關文章
相關標籤/搜索