django學習之Model(四)MakingQuery

來源:互聯網
上載者:User

標籤:style   blog   http   color   使用   io   資料   for   

上一篇寫到MakingQuey中的filter,本篇接著來。

 10)-擴充多值的關係

如果對一個ManyToManyField或ForeignKey的表進行filter過濾查詢的話,有2中方法可以用。分別是:

#1Blog.objects.filter(entry__headline__contains=‘Lennon‘,        entry__pub_date__year=2008)#2Blog.objects.filter(entry__headline__contains=‘Lennon‘).filter(        entry__pub_date__year=2008)

假設,現有一個blog表,它對應了很多的entry的表,而且這個blog既有含有“Lennon”的entry,也有含有2008的entry,但是沒有那種2者都有的entry,那麼第一個方法過濾的是2者都有的entry,所以沒有合格blog返回。第一種方法可以理解為“並且”的意思。第二種是第一個filter返回含有“Lennon”的blog,然後在這個blog集合中,再選有2008的,所以會有blog返回。開始理解起來很費勁,抓住特點:一個blog對應多個entry。例如,blog1對應了entry1,entry2,entry3,其中entry1隻有“Lennon”,沒有2008;entry2隻有2008,沒有“Lennon”;entry3則什麼都沒有。那麼用第一種方法來filter的時候,則沒有滿足既有Lennon又有2008的entry;第二種方法的第一個filter,因為entry1有Lennon,所以blog1為傳回值,然後對傳回值blog1進行filter,條件為有2008,而blog1中的entry2是有2008的,所以blog1作為傳回值。

這個也適用於exlude().

11)-filters可以引用model中的fields

class F

目前為止的例子中,都是用field中的值來作為filter的條件來進行資料查詢。但是如果需要把一個field的值與他所在的model的其他field的值呢?

django提供F()運算式來實現這種比較。F()的執行個體是在一個query中來對model中的field進行引用。這些引用可以作為filter的條件來進行過濾。

例如,要查詢blog的entry,comments滿足的數量比pingbacks的多,可以用F()來作用在pingbacks上,然後把結果作為filter的條件:

>>> from django.db.models import F>>> Entry.objects.filter(n_comments__gt=F(‘n_pingbacks‘))

注意:F()運算式中是n_comments比大n_pingbacks。所以,也有倍數、加、減這樣的操作可以來比較:

>>> Entry.objects.filter(n_comments__gt=F(‘n_pingbacks‘) * 2)#
n_comments比n_pingbacks的2倍多

>>> Entry.objects.filter(rating__lt=F(‘n_comments‘) + F(‘n_pingbacks‘))#n_comments與n_pingbacks的和比rating多

gt是多理解為>,lt理解為<. 

而下面的例子則是兩個字串一樣:

>>> Entry.objects.filter(authors__name=F(‘blog__name‘))

12)-pk

是primary key的意思:

>>> Blog.objects.get(id__exact=14) # Explicit form>>> Blog.objects.get(id=14) # __exact is implied>>> Blog.objects.get(pk=14) # pk implies id__exact
# Get blogs entries with id 1, 4 and 7>>> Blog.objects.filter(pk__in=[1,4,7])# Get all blog entries with id > 14>>> Blog.objects.filter(pk__gt=14)

同樣應該有這些符號的組合,分別是__雙底線,lt,gt,exact等等。

如果查詢含有%符號的,下例給出:

>>> Entry.objects.filter(headline__contains=‘%‘)

同樣的_底線符號也是,django會自動來處理的,就像上邊這行程式這樣寫就行了。

5-QuerySet的緩衝

每個QuerySet都有緩衝來降低對資料庫database的訪問。弄明白了之後,可以寫出高效率的代碼。

在新建立的QuerySet中,緩衝是空的。當QuerySet第一次 被計算的時候,django把QuerySet放在其緩衝中,然後把具體要查詢的資料項目作為結果返回。把QuerySet這種緩衝的行為時刻記住,有的時候很容易使用不當的。例如下面,建立了2個QuerySet,分別使用後,就丟掉了,這樣造成了2次訪問database,而且第二個e很可能不是第一個e,因為在第二個發生之前,database很可能已經被寫入新資料或刪除什麼東西了:

>>> print([e.headline for e in Entry.objects.all()])>>> print([e.pub_date for e in Entry.objects.all()])

正確的做法如下,建立個變數來存放QuerySet,讓它一直放在記憶體中,然後每次用的時候從記憶體中去讀取:

>>> queryset = Entry.objects.all()>>> print([p.headline for p in queryset]) # Evaluate the query set.>>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.

注意,第一行並沒有touch the database,訪問資料庫發生在第二行代碼。

QuerySet也並不是總緩衝結果的,當計算queryset的一部分的時候,要緩衝,但是如果只是用一個下一層的queryset來訪問結果的時候,並沒有緩衝。這也意味著,可以用數組分區或者一個索引來限制queryset而不產生緩衝,例如下面的例子,顯示只定義了一個queryset來存放objects,然後用數組來訪問其中的某一個,這樣就沒有緩衝,每次都要重新訪問資料庫:

>>> queryset = Entry.objects.all()>>> print queryset[5] # Queries the database>>> print queryset[5] # Queries the database again

然而,如果整個queryset都被計算了,那麼就會產生緩衝:

>>> queryset = Entry.objects.all()>>> [entry for entry in queryset] # Queries the database>>> print queryset[5] # Uses cache>>> print queryset[5] # Uses cache

還有一些例子也是整個querset都被計算了,當然產生了緩衝:

>>> [entry for entry in queryset]>>> bool(queryset)>>> entry in queryset>>> list(queryset)

6-用Q對象來進行複雜的查詢

在filter()方法中,用關鍵字來查詢,這些關鍵字是AND的關係,即”並且“,如果需要進行更複雜的查詢,例如OR關係,可以用Q對象這種方法。

Q對象(django.db.models.Q)是用來封裝關鍵字的集合的。這些關鍵字包括上文的lookup查詢中所提到的關鍵字。例如,下面這個Q對象封裝了LIKE查詢:

from django.db.models import QQ(question__startswith=‘What‘)

Q對象可以用邏輯符號&或者|來串連,結果返回一個Q對象:

Q(question__startswith=‘Who‘) | Q(question__startswith=‘What‘)

同等於SQL語句:

WHERE question LIKE ‘Who%‘ OR question LIKE ‘What%‘

可以把Q對象組合成複雜的表達,也可以用~符號,代表”NOT,非“的意思:

Q(question__startswith=‘Who‘) | ~Q(pub_date__year=2005)

每個查詢函數(filter(), get(), exclude())都需要有關鍵字,Q對象就可以作為這些查詢函數的關鍵字:

Poll.objects.get(    Q(question__startswith=‘Who‘),    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

翻譯成SQL語句就相當痛苦了:

SELECT * from polls WHERE question LIKE ‘Who%‘    AND (pub_date = ‘2005-05-02‘ OR pub_date = ‘2005-05-06‘)

查詢函數也可以混合使用keywords和Q object,但是要注意,Q object必須在keyword之前定義:

#正確的Poll.objects.get(    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),    question__startswith=‘Who‘)
#錯誤的Poll.objects.get(    question__startswith=‘Who‘,    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))

 7-比較對象

用python標準的比較操作符==就可以進行model執行個體的比較。而這實際上實在比較primarykey的值:

>>> some_entry == other_entry>>> some_entry.id == other_entry.id#實際上

如果model的primarykey不叫id,沒關係,照樣還是在比較primarykey,例如一個model的primarykey是name,則下面2行代碼是同樣意思的:

>>> some_obj == other_obj>>> some_obj.name == other_obj.name

8-刪除對象

delete()用來進行對象的刪除,而且是立即生效,並且沒有傳回值:

e.delete()

也可以批量來進行刪除操作,每個QuerySet都有delete()操作,可以把QuerySet中的所有對象都刪掉:

Entry.objects.filter(pub_date__year=2005).delete()

delete是Manager的一個方法,但是由於怕使用者誤操作而沒有顯式的顯現出來。因為delete是純粹的在SQL中執行的方法,所以不需要使用者在過程中去認為的調用。如果你在一個model的class定義中自己定義了一個delete()的話,那麼就相當於覆蓋掉了Manager提供的delete,這樣就需要使用者自己去調用了,而且這種自己定義的delete()還不能批量的來操作,也就是不能作為QuerySet中的參數來調用,而是需要自己對每個object單獨進行delete一次。

django提供的delete()方法,會刪除由foreignkey來關聯到一起的object:

b = Blog.objects.get(pk=1)# This will delete the Blog and all of its Entry objects.b.delete()

這種串聯的用法是通過 on_delete 參數傳遞給Foreignkey的。

delete是Manager的一個方法,為了防止使用者誤操作,所以不用顯式調用,但是如果確實需要調用delete()來刪除所有的objects的話,應該明確的指出來這個QuerySet:

Entry.objects.all().delete()

9-複製model執行個體

儘管沒有built-in的方法來實現model 執行個體的複製,但是可以用model的所有的fields的值來建立一個新的執行個體,最簡單的情況就是,先把pk設定成None,然後再save:

1 blog = Blog(name=‘My blog‘, tagline=‘Blogging is easy‘)2 blog.save() # blog.pk == 13 4 blog.pk = None5 blog.save() # blog.pk == 2

思考:也就是,第1行代碼只是把Blog內容放在了blog這個變數中,並沒寫進去資料庫,只有調用save()方法時,才發生寫的操作。而且每當調用save(),都相當於要把這個資料(blog)寫進資料庫。而資料庫的pk是唯一而不能重複的,所有先要把blog.pk設成None,然後再操作,由SQL語句把pk由依次遞增為2了。

如果有model的繼承時,會略複雜一些:

class ThemeBlog(Blog):    theme = models.CharField(max_length=200)django_blog = ThemeBlog(name=‘Django‘, tagline=‘Django is easy‘, theme=‘python‘)django_blog.save() # django_blog.pk == 3

因為繼承的工作原理,這次需要把pk和id都設成None了:

django_blog.pk = Nonedjango_blog.id = Nonedjango_blog.save() # django_blog.pk == 4

這個過程並沒有複製相關聯的objects,如果想要複製這種關係,需要多寫一些代碼了。在本文的例子中,Entry和Author是多對多的關係(ManyToManyField):

1 entry = Entry.objects.all()[0] # some previous entry2 old_authors = entry.authors.all()3 entry.pk = None4 entry.save()5 entry.authors = old_authors # saves new many2many relations

今天到這,明天繼續!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.