django学习之Model(四)MakingQuery
上一篇寫到MakingQuey中的filter,本篇接著來。
?10)-擴展多值的關系
如果對一個ManyToManyField或ForeignKey的表進行filter過濾查詢的話,有2中方法可以用。分別是:
#1 Blog.objects.filter(entry__headline__contains='Lennon',entry__pub_date__year=2008)#2 Blog.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 Q Q(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.name8-刪除對象
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 == 1 3 4 blog.pk = None 5 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 = None django_blog.id = None django_blog.save() # django_blog.pk == 4這個過程并沒有復制相關聯的objects,如果想要復制這種關系,需要多寫一些代碼了。在本文的例子中,Entry和Author是多對多的關系(ManyToManyField):
1 entry = Entry.objects.all()[0] # some previous entry 2 old_authors = entry.authors.all() 3 entry.pk = None 4 entry.save() 5 entry.authors = old_authors # saves new many2many relations今天到這,明天繼續!
轉載于:https://www.cnblogs.com/ee2213/p/3919669.html
總結
以上是生活随笔為你收集整理的django学习之Model(四)MakingQuery的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: div+css相对定位和绝对定位
- 下一篇: 【Open Search产品评测】-