Django資料庫查詢優化與AJAX
- 2019 年 12 月 16 日
- 筆記
資料庫設計三大範式
第一範式(1NF):列不可再分(原子性)
每一列屬性都是不可再分的,兩列的屬性相近或相似或一樣,應盡量合併屬性一樣的列,確保不產生冗餘數據。
第二範式(2NF):屬性完全依賴路主鍵(唯一性)
第二範式是在第一範式的基礎上建立起來的,也就是第二範式要求資料庫表中的每個實例或行必須可以被唯一的區分,也就是一張表至少有一個主鍵來區分每一條記錄。
第三範式(3NF):屬性不依賴於其他非主鍵屬性,屬性直接依賴於主鍵(冗餘性)
不同的屬性之間不能有傳遞關係,也就是每一個屬性的數據不能相互影響。
orm相關的資料庫查詢優化
惰性查詢
惰性查詢指當我們只查資料庫而不是用這些數據時,Django不會執行查詢資料庫的程式碼,目的是減少不必要的資料庫操作,降低資料庫的壓力。
如:
res = models.Book.objects.all()#只有當我們使用res時才會執行資料庫查詢的操作
all、only與defer
all
拿到自己的所有的屬性,但是沒有與其他表建立外鍵的屬性。
only
only括弧內放欄位,查詢結果是一個列表套一個個數據對象,這些數據對象點括弧內的欄位屬性,不會再查資料庫,直接就是對象獲取屬性;也支援點其他屬性,但是其他屬性會每拿一條數據就走一次資料庫。
res = models.Book.objects.only('name')#查詢一次 print(res) for i in res: print(i.name) res = models.Book.objects.only('name')#查詢多次 print(res) for i in res: print(i.price)
defer
defer與only是互為反操作,點括弧內的屬性會每拿一條數據就走一次資料庫,點其他的屬性反而只走一次資料庫。
res = models.Book.objects.defer('name')#查詢多次 print(res) for i in res: print(i.name) res = models.Book.objects.defer('name')#查詢一次 print(res) for i in res: print(i.price)
select_related與prefetch_related
select_related
括弧內只能放一對一、一對多的外鍵欄位,特點:內部自動連表操作,會將括弧內外鍵欄位所關聯的表與當前表自動拼接成一張表,然後將表中的數據一個一個查詢出來封裝成一個一個的對象。
這樣做的好處:跨表查詢也不需要重複走資料庫,減輕資料庫壓力。select_related()括弧內放多個外鍵欄位,逗號隔開,會將多個外鍵欄位關聯的表與當前表拼成一張大表。
耗時:資料庫層面連表操作,當資料庫特別大時可能連表的時間會長一點,用prefetch_related可能會好一點,但如果表比較小兩者基本沒太大差別。
res = models.Book.objects.select_related('publisher') for i in res: print(i.publisher.publisher_name)
prefetch_related
prefetch_related內部是子查詢(當一個查詢是另一個查詢的條件時,稱之為子查詢。),特點:按步驟查詢多張表,然後將查詢結果封裝到對象中,給用戶的感覺好像還是連表操作,括弧內支援傳多個外鍵欄位,每放一個外鍵欄位就會多走一條SQL語句,多查一張表。
使用:主要用於多對多欄位和一對多欄位
耗時:查詢的次數上
res = models.Book.objects.prefetch_related('publisher') for i in res: print(i.publisher.publisher_name)
MTV與MVC模型
MTV(models templates views)
models templates views:模型層、模板層、視圖層
Django自稱是MTV框架,其實本質還是MCV
MCV(models views controllar)
models views controllar:模型層、視圖層、控制層
controllar指url(路由匹配)
choices參數
choices參數指一個欄位只有幾個情況可以選擇,比如性別欄位只有兩個情況,類似的還有在職狀態、學歷、婚否等。
我們可以用0、1等數字代表男女等欄位可能的情況,將數字存入表中(可以是數字也可以是字元串,通常用-1表示數據短缺或者數據丟失),取出的時候如果存儲的數字在提前定義好的關係中會,則會取出對應關係的字元串,如果沒有對應關係,取出的還是數字。
choices欄位類型在獲取值的時候統一句式:get_欄位名_display()
class User(models.Model): username = models.CharField(max_length=64) password = models.IntegerField() gender_choices = ( (1,'男'), (2,'女'), (3,'其他'), ) gender = models.IntegerField(choices=gender_choices)
Ajax(重要)
AJAX簡介
AJAX(Asynchronous Javascript And XML)「非同步的Javascript和XML」,即使用Javascript語言與伺服器進行非同步交互,傳輸的數據為XML(當然,傳輸的數據不只是XML)。
AJAX 不是新的程式語言,而是一種使用現有標準的新方法。
AJAX 最大的優點是在不重新載入整個頁面的情況下,可以與伺服器交換數據並更新部分網頁內容。(這一特點給用戶的感受是在不知不覺中完成請求和響應過程)
AJAX 不需要任何瀏覽器插件,但需要用戶允許JavaScript在瀏覽器上執行。
- 同步交互:客戶端發出一個請求後,需要等待伺服器響應結束後,才能發出第二個請求;
- 非同步交互:客戶端發出一個請求後,無需等待伺服器響應結束,就可以發出第二個請求。
AJAX的應用場景
搜索引擎根據用戶輸入的關鍵字,自動提示檢索關鍵字,網站註冊時候的實時用戶名的查重,特點:
- 不刷新頁面的前後端數據交互
- 非同步操作,當請求發出後,瀏覽器還可以進行其他操作
AJAX前的知識儲備
XML簡單介紹
XML是一門標記語言,它的應用場景有:
1.寫配置文件
2.寫前端頁面如odoo框架(公司內部管理軟體開發框架,內部功能的實現全部依賴於python2)中的erp。
JSON簡介
- JSON 指的是 JavaScript 對象表示法(JavaScript Object Notation)
- JSON 是輕量級的文本數據交換格式
- JSON 獨立於語言 *
- JSON 具有自我描述性,更易理解
* JSON 使用 JavaScript 語法來描述數據對象,但是 JSON 仍然獨立於語言和平台。JSON 解析器和 JSON 庫支援許多不同的程式語言。
前端JAON對象與Python json模組的對應關係:

stringfy和parse方法
JavaScript中關於JSON對象和字元串轉換的兩個方法:
JSON.parse(): 用於將一個 JSON 字元串轉換為 JavaScript 對象(json只認雙引的字元串格式)
JSON.parse('{"name":"ylpb"}'); JSON.parse('{name:"ylpb"}') ; // 錯誤 JSON.parse('[18,undefined]') ; // 錯誤
JSON.stringify(): 用於將 JavaScript 值轉換為 JSON 字元串。
JSON.stringify({"name":"Tonny"})
經過json序列化的數據以字元串的數據類型存儲的,這點是必須要清楚的,如
b = json.dumps({'password': 123}) print(type(b)) #<class 'str'> print(b) #{"password": 123} #這點容易造成誤解因為我們看到的好像並不是一個字元串
ajax基本語法結構:
$.ajax({ url:'', // 數據提交的後端地址 不寫就是往當前頁面提交 也可以寫後綴 也可以寫全稱 跟actions一樣 type:'post', // 提交方式 默認是get請求 data:{'i1':$('#d1').val(),'i2':$('#d2').val()}, // 提交的數據 success:function (data) { // 形參data就是非同步提交之後後端返回結果 $('#d3').val(data) // 回調機制需要做的事情 } })
前後端傳輸數據的編碼格式
前後端進行數據交互的時候,針對不同的數據後端會進行不同的處理,Django中的request.POST、request.GET、request.FILES
前端向後端發送數據的時候需要指定數據編碼格式,目前我們需要了解的有三種:urlencoded、formdata、json
form表單向後端發送數據的編碼格式有兩種,第一種是我們沒有配置enctype時,它默認的編碼格式是urlencoded,當我們發送文件時需要將enctype設置成 multipart/form-data,這樣form表單發送文件的時候就採用formdata的格式進行編碼。但是問題來了前端如何向後端發生json格式的數據呢?這個時候只能藉助於AJAX才能完成json格式數據的發送,AJAX可以發送上述的三種編碼格式的數據
AJAX如何傳輸json數據
前端程式碼:
$('#d1').click(function () { $.ajax({ url:'', type:'post', contentType:'application/json', # 1.注意點1 data:JSON.stringify({'username':'ylpb','password':'123'}), # 2.注意點2 success:function (data) { alert(123) } }) })
說明:
1.需要設置contentType:'application/json'。
2.對JSON數據進行序列化。
3.Django後端針對json格式的數據不會做任何的處理,只是將數據原封不動的放在了request.body中,我們需要手動對其進行反序列化處理。
AJAX發送文件
<form action=""> username:<input type="text" name="username"> password:<input type="text" name="password"> myfile:<input type="file" name="myfile" id="d2"> </form> <button id="d1">點我發送文件數據</button> <script> // 傳文件 $('#d1').click(function () { // 先生成一個內置對象 var MyFormData = new FormData(); // 1. 先添加普通的鍵值 MyFormData.append('username','ylpb'); // 添加了一組普通的簡直對,append後面第一個參數是鍵,第二個參數是值 MyFormData.append('password','123'); MyFormData.append('hobby',['read','run']); // 2. 添加文件數據MyFormData.append(文件名,文件數據) MyFormData.append('myfile',$('#d2')[0].files[0]); // 獲取input框中文件對象的方法:$('#d2')[0].files[0] 方法介紹:找到id為d2(input框的id)的jQuery對象$('#d2'),然後索引0拿到標籤對象即$('#d2')[0],然後使用files方法獲取文件數據 $.ajax({ url:'', type:'post', data:MyFormData, // 發送文件必須要指定的兩個參數 contentType:false, // 不使用任何編碼 MyFormData對象內部自帶編碼 django後端能夠識別 processData:false, // 不要瀏覽器處理數據 success:function (data) { } }) }) </script>
Django後端可以自動識別MyFormData(我們自己生成的內置對象)中的普通鍵值和文件,普通鍵值放在request.POST裡面,文件放在request.FILES裡面。
序列化
序列化的目的就是將數據整合成一個大的字典的形式方便數據交互。
Django內置的serializers模組
前端想拿到通過orm查到的一個個對象,(資料庫里的一條條記錄),後端想把直接實例化出來的對象發送給前端,這時候就需要用到Django給我們提供的序列法方式(其實就是列表套字典的形式將數據發送出去)。
使用方法:
def ser(request): #拿到用戶表裡面的所有的用戶對象 user_list=models.User.objects.all() #導入內置序列化模組 from django.core import serializers #調用該模組下的方法,第一個參數是你想以什麼樣的方式序列化你的數據 ret=serializers.serialize('json',user_list) return HttpResponse(ret)