Django lazy load 懶加載 倒序查詢


Django orm默認懶加載
  ###Django orm默認使用的懶加載,即使用的時候才去訪問數據庫,且每次默認取最少的數據,當然這樣有好處也有壞處... - #### 壞處: 會導致頻繁的查詢數據庫,如涉及到外鍵的時候,會先去取需要的數據集,再取外鍵的數據集,等於訪問了兩次數據庫,那取n條數據就訪問了n*n次數據庫 如查詢語句: models.Article.objects.all() 當Article表中關聯author、tag、categroy等外鍵字段時,你取一條數據,他需要去訪問4次數據庫,三外鍵加本身。 - #### 好處: 顯然的當你執行: models.Article.objects.all() 這樣的語句,如果一次全部查詢把所有數據給你返回,你是小網站,數據小無所謂,數據大了內存就爆炸了! ####django orm的策略是,懶加載: #####即:res = models.Article.objects.all()這樣的所有查詢、obj = models.Article('title'='xxx', 'body' = 'xxx') 等語句時。 ##### 並沒有真正去數據庫操作取出、生成數據,而是生成Query_set迭代對象  .create() 和.update()語句會保存的同時直接去數據庫創建 而在執行res[0].title、res[10],body 還有obj.save()這樣的語句時才真正的去執行SQL語句,操作數據庫,取數據,保存數據。 第一個很直觀的一堆Query_set對象中沒有取回數據,當然占用內存就小很多了。 而當每次查詢回來數據,Django就會把這些數據保存在cache中,當你下次使用時,不會去數據庫再次查詢,而是去cache里面取。
二、升降序、結果集
- ####結果集 Django 的數據查詢基於構建結果集及對結果集進行取值. 結果集是獨立於數據庫的符合某個查詢條件的一組數據對象的集合.這是一個惰性集合:在對該集合取值之前,無法知道該集合有哪些成員.   要生成一個滿足你需求的結果集,首先要得到一個描述給定類型的所有對象的初始結果集.這個初始結果集可以通過一系列函數進行更精細的優化處理.當經過處理后的結果集符合你的要求時, 就可以對它進行取值操作(使用迭代操作,slicing操作,或一系列其它技術), 以得到一個你需要的對象或對象的列表.   獲得初始結果集 每個 Django model 都有一個與生俱來的管理器對象 objects, 管理器最重要的角色就是作為初始結果的來源. 一個管理器就是一個描述給定類型所有對象的特殊的初始結果集. Article.objects 就是包含所有 Poll 對象的一個初始結果集. 它唯一特殊之處在於它不能被取值. 要克服此限制, 管理器對象有一個 all() 方法. 該方法生成一個 可以 被取值的初始結果集的拷貝:   res = models.Article.objects.all() Article.objects.all()[:-11:-1] 取最后10個對象 Article.objects.all()[0:10] 取前10個對象 結果集對象是惰性對象 - 也就是說,他們不是 真正的 包含他們表示對象的集合 (或列表). Python 的協議魔法讓結果集看起來是一個可迭代,可切片的對象. 事實上在幕后, Django 使用了緩存技術..   如非要把它們變成列表。那只能強制取值了:   querylist = list(Article.objects.all()) #這兒可以理解為 list(dict.keys())一樣的感覺,把 對象變為列表 不過,最好不要這么做,特別是在該集合相當大時. Django 每創建一個對象都需要內存,將占用相當大的內存.   可理解為生成器 genrator = (x for x in range(10000000)) 和列表生成式 list = [i for i in range(100000000)] 的區別 前者是一個生成器對象,當需要數據時,根據規則去生成,而后者是實實在在在內存中存在的大列表  
2.2 升降序
#### .order_by()語句 order_by('id')’默認升序 ASC ####在order_by('-id')和order_by('-pub_time') 排序字段名前加 - 減號表示降序 DESC res = models.Article.objects.all().order_by('id') 按照id正向排序 - #### reverse()方法反向排序 res.reverse()[:5] 注意,這與Python 中從一個序列的末尾進行切片有點不一樣。上面的例子將首先返回最后一個元素,然后是倒數第二個元素,依此類推。如果我們有一個Python序列,當我們查看list[-5:]時,我們將一下子得到倒數五個元素。Django不支持這種訪問模型(從末尾進行切片),因為它不可能利用SQL高效地實現。   同時還要注意,reverse() 應該只在一個已經定義排序的QuerySet上調用(例如,在一個定義了默認排序的模型上,或者使用order_by()的時候)。如果QuerySet沒有定義排序,調用reverse()將不會有任何效果
三、倒序查詢
###本來這片文章的起因就是作者在寫一個查詢語句,我只需要最后更新的10個數據。我就在想如果是用SQL語句很簡單: 但是如果使用Query_set 來查詢,不管我是正序還是倒序,都會返回巨大的數據量。就開始去了解Django的Query_set 查詢策略
from django.db import models

class Article(models.Model):
    
    title = models.CharField(max_length= 64)
    body = models.TextField()
    pub_time = models.DateTimeField(auto_now_add= True)

    class Meta:
        get_latest_by = 'pub_time'
  • 幾種反向查詢策略:以上表為例

order_by() 語句:
models.Article.objects.all().order_by('-id) 或者 order_by('-pub_time')
 
反向切片訪問:
models.Article.objects.fiter(id__gte=0)[::-1] 完全反向切片
 
reverse()函數
models.Article.objects.all().order_by('id').reverse()

3.2 訪問最后一個元素
- 通過.frist()訪問第一個元素,.last()訪問最后一個元素. models.Article.objects.all().last()
  • latest(self, *fields, field_name=None) 函數訪問

根據 model 的 'get_latest_by' 選項或可選的字段名參數返回最新的對象. 例子:
 
Article.objects.latest()
 
Article.objects.latest('expire_date')

如果模型的Meta指定get_latest_by,則可以將field_name參數留給earliest()或者 latest()。默認情況下,Django將使用get_latest_by中指定的字段。

get_latest_by

由於Django的管理方法中有個lastest()方法,就是得到最近一行記錄。如果你的數據模型中有 DateField 或 DateTimeField 類型的字段,你可以通過這個選項來指定lastest()是按照哪個字段進行選取的。

一個 DateField 或 DateTimeField 字段的名字. 若提供該選項, 該模塊將擁有一個 get_latest() 函數以得到 "最新的" 對象(依據那個字段):

四、字段查找

exact、iexact

exact:精確匹配。區分大小寫

例如:

Entry.objects.get(id__exact=14)

Entry.objects.get(id__exact=None)

iexact:不區分大小寫的精確匹配

例如:

Blog.objects.get(name__iexact='beatles blog')

Blog.objects.get(name__iexact=None)

contains、icontains

contains:包含,大小寫敏感

例如:

Entry.objects.get(headline__contains='Lennon')

icontains:包含,大小寫不明感.

例如:

Entry.objects.get(headline__icontains='Lennon')

in

在一個給定的列表中.

Example:

Entry.objects.filter(id__in=[1, 3, 4])

gt、gte、lt、lte

gt:大於

例子:

Entry.objects.filter(id__gt=4)

gte:大於或等於

lt:小於

lte:小於或等於

startswith、istartswith、endswith、iendswith

startswith:區分大小寫,開始位置匹配

例如:

Entry.objects.filter(headline__startswith='Will')

istartswith:不區分大小寫,開始位置匹配

endswith:區分大小寫,結束位置匹配

iendswith:不區分大小寫,結束位置匹配

range

范圍

例如:

import datetime

start_date = datetime.date(2005, 1, 1)

end_date = datetime.date(2005, 3, 31)

Entry.objects.filter(pub_date__range=(start_date, end_date))

等價SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

year、month、day

year: 返回精確的年份

例如:

Entry.objects.filter(pub_date__year=2005)

等價SQL:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';

month: 對於月份時間字段,匹配一個整數從1 (January)到 12 (December).

day: 對於日期和日期時間字段,具體到某一天的匹配。取一個整數的天數。

isnull

值為 True 或False, 相當於SQL語句IS NULL和IS NOT NULL.

例如:

Entry.objects.filter(pub_date__isnull=True)

等價SQL:

SELECT ... WHERE pub_date IS NULL;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM