django orm總結

django orm總結

目錄
1.1.1 生成查詢
1.1.2 創建對象
1.1.3 保存修改的對象
1.1.4 保存 ForeignKey 和 ManyToManyField 字段
1.1.5 檢索對象
1.1.6 檢索所有的對象
1.1.7 過濾檢索特定對象
1.1.8 鏈接過濾
1.1.9 過濾結果集是唯一 
1.2.1 結果集是延遲的 
1.2.2 其他的QuerySet方法
1.2.3 限制 QuerySets
1.2.4 字段查找
1.2.5 跨關係查詢
1.2.6 過濾器可參考模型字段
1.2.7 緩存查詢集
1.2.8 比較對象
1.2.9 刪除對象
1.3.1 一次修改多個對象
1.3.2 關係對象
1.3.3 One-to-many關係
1.3.4 Many-to-many關係
1.3.5 One-to-one關係


1.1.1 生成查詢
你創建完數據模型,django會自動提供給你數據庫抽象的API,可以創建、獲取、修改、刪除對象,本篇文檔講解如何使用API。

我們參考下面模型,一個weblog:

複製代碼
#博客
class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __unicode__(self):
        return self.name
#作者
class Author(models.Model):
    name = models.CharField(max_length=50)
    email = models.EmailField()

    def __unicode__(self):
        return self.name

#目錄
class Entry(models.Model):
    blog = models.ForeignKey(Blog)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateTimeField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __unicode__(self):
        return self.headline
複製代碼

 

1.1.2 創建對象

用python對象描述數據庫表的數據,django使用一個直觀的系統,一個模型類描述一個數據表,一個類的實例描述表的一條詳細記錄。使用模型的save()方法將對象創建到數據庫。

from mysite.blog.models import Blog

b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()

只有執行save方法時,django纔會執行sql把對象寫入數據庫。


1.1.3 保存修改的對象

保存修改仍然使用save()方法

b5.name = 'New name'
b5.save()


1.1.4 保存 ForeignKey 和 ManyToManyField 字段

cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog #爲 ManyToManyField 增加記錄
entry.save()

joe = Author.objects.create(name="Joe")
entry.authors.add(joe) #爲 ForeignKey 增加記錄


1.1.5 檢索對象
從數據庫裏檢索對象,可以通過模型的Manage來建立QuerySet,一個QuerySet表現爲一個數據庫中對象的結合,他可以有0個一個或多個過濾條件,在SQL裏QuerySet相當於select語句用where或limit過濾。你通過模型的Manage來獲取QuerySet,每個模型至少有一個Manage


1.1.6 檢索所有的對象

檢索表中所有數據,最簡單的方式是用all().

all_entries = Entry.objects.all()


1.1.7 過濾檢索特定對象

檢索過濾特定查詢結果,有兩個方法。
filter(**kwargs) 返回一個新的匹配查詢參數後的QuerySet 
exclude(**kwargs) 返回一個新的不匹配查詢參數後的QuerySet

Entry.objects.filter(pub_date__year=2006)


1.1.8 鏈接過濾

Entry.objects.filter(headline__startswith='What')
         .exclude(pub_date__gte=datetime.now())
         .filter(pub_date__gte=datetime(2005, 1, 1))


1.1.9 過濾結果集是唯一

每次你完成一個QuerySet,你獲得一個全新的結果集,不包括前面的。每次完成的結果集是可以貯存,使用或複用
q1 = Entry.objects.filter(headline__startswith="What")
q2 = q1.exclude(pub_date__gte=datetime.now())
q3 = q1.filter(pub_date__gte=datetime.now())

三個QuerySets是分開的,第一個是headline以"What"單詞開頭的結果集,第二個是第一個的子集,即pub_date不大於現在的,第三個是第一個的子集 ,pub_date大於現在的


1.2.1 結果集是延遲的

QuerySets是延遲的,創建QuerySets不會觸及到數據庫操作,你可以多個過濾合併到一起,直到求值的時候django纔會開始查詢。如:

q = Entry.objects.filter(headline__startswith="What")
q = q.filter(pub_date__lte=datetime.now())
q = q.exclude(body_text__icontains="food")
print q

雖然看起來執行了三個過濾條件,實際上最後執行print q的時候,django纔開始查詢執行SQL到數據庫。


1.2.2 其他的QuerySet方法
大多數情況你使用all()、filter()和exclude()


1.2.3 限制 QuerySets

使用python的數組限制語法限定QuerySet,如:
取前5個

Entry.objects.all()[:5]

 

取第五個到第十個

Entry.objects.all()[5:10]

 

一般的,限制QuerySet返回新的QuerySet,不會立即求值查詢,除非你使用了"step"參數

Entry.objects.all()[:10:2]
Entry.objects.order_by('headline')[0]
Entry.objects.order_by('headline')[0:1].get()


1.2.4 字段查找

字段查找是指定SQL語句的WHERE條件從句,通過QuerySet的方法filter(), exclude()和get()指定查詢關鍵字。
基本查詢field__lookuptype=value
例如:

Entry.objects.filter(pub_date__lte='2006-01-01')

轉換爲SQL:

SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

如果你傳了無效的參數會拋異常

 

數據庫API 支持一些查詢類型,下面體驗一下:
a、exact

Entry.objects.get(headline__exact="Man bites dog")

等價於

SELECT ... WHERE headline = 'Man bites dog';

如果查詢沒有提供雙下劃線,那麼會默認 __exact=

Blog.objects.get(id__exact=14) # Explicit form
Blog.objects.get(id=14) # __exact is implied

b、iexact——忽略大小寫

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

blog title會匹配 "Beatles Blog", "beatles blog", 甚至 "BeAtlES blOG".

c、contains——包含查詢,區分大小寫

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

轉化爲SQL

SELECT ... WHERE headline LIKE '%Lennon%';

icontains 不區分大小寫

startswith,endswith,istartswith,iendswith
前模糊匹配,後模糊匹配


1.2.5 跨關係查詢

Entry.objects.filter(blog__name__exact='Beatles Blog')

這個可以跨越你想要的深度。

反向跨關係查詢

Blog.objects.filter(entry__headline__contains='Lennon')


如果跨越多層關係查詢,中間模型沒有值,django會作爲空對待不會發生異常。

Blog.objects.filter(entry__author__name='Lennon');
Blog.objects.filter(entry__author__name__isnull=True);
Blog.objects.filter(
entry__author__isnull=False,
entry__author__name__isnull=True);


1.2.6 過濾器可參考模型字段

目前給的例子裏,我們建立了過濾,比照模型字段值和一個固定的值,但是如果我們想比較同一個模型裏的一個指端和另一個字段的值,django提供F()——專門取對象中某列值的操作

from django.db.models import F
Entry.objects.filter(n_pingbacks__lt=F('n_comments'))

注:n_pingbacks、n_comments爲模型Entry屬性

django支持加減乘除和模計算

Entry.objects.filter(n_pingbacks__lt=F('n_comments') * 2) 
Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks')) 
Entry.objects.filter(author__name=F('blog__name'))

 

主鍵查詢捷徑

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

 

不僅限於__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)

 

跨越查詢

Entry.objects.filter(blog__id__exact=3) # Explicit form
Entry.objects.filter(blog__id=3) # __exact is implied
Entry.objects.filter(blog__pk=3) # __pk implies __id__exact

 

like語句轉義百分號

Entry.objects.filter(headline__contains='%')

轉義爲

SELECT ... WHERE headline LIKE '%\%%';


1.2.7 緩存查詢集

每個QuerySet都包含一個緩存,以儘量減少對數據庫的訪問。理解他的工作原理很重要,可以寫出最高效的代碼。
在最新創建的QuerySet裏,緩存是空的。在第一次QuerySet被取值,因此數據庫查詢發生,django把查詢結果放入緩存,並返回給請求,隨後的查詢取值會複用緩存中的結果。

保持緩存的思想習慣,因爲如果你不正確使用查詢緩存會有麻煩。例如下面例子會創建兩個QuerySet

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

這樣意味着數據庫查詢會執行兩次,實際兩次數據庫加載

爲了避免這個問題,簡單保存QuerySet複用

queryset = Poll.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.


1.2.8 比較對象

比較兩個模型實例,使用python標準的運算符,兩個等號==

some_entry == other_entry
some_entry.id == other_entry.id
some_obj == other_obj
some_obj.name == other_obj.name


1.2.9 刪除對象

刪除方法是很方便的,方法名爲delete(),這個方法直接刪除對象沒有返回值

e.delete()

你也可以批量刪除對象,每個QuerySet有一個delete()方法,能刪除 QuerySet裏所有對象


1.3.1 一次修改多個對象

有時候你想給QuerySet裏所有對象的一個字段賦予特定值,你可以使用 update()方法
例如:

# Update all the headlines with pub_date in 2007.
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

 

這個方法只能用於無關聯字段和外鍵

b = Blog.objects.get(pk=1)
# Change every Entry so that it belongs to this Blog.
Entry.objects.all().update(blog=b)

 

update()方法不返回任何值,QuerySet不支持save方法,如果要執行save,可以如下:

for item in my_queryset:
item.save()

 

update也可以使用F()

# THIS WILL RAISE A FieldError
Entry.objects.update(headline=F('blog__name'))

 

1.3.2 關係對象

當你在model裏定義一個關係時,模型實例會有一個方便的API來訪問關係對象。用本頁上面的模型舉個例子,一個Entry
對象可以得到blog對象,訪問blog屬性e.blog。
django也創建API來訪問關係對象的另一邊,一個blog對象訪問Entry列表b.entry_set.all().


1.3.3 One-to-many關係

如果一個對象有ForeignKey,這個模型實例訪問關係對象通過簡單的屬性

e = Entry.objects.get(id=2)
e.blog # Returns the related Blog object.

你可以憑藉外鍵屬性獲取和賦值,修改外鍵值知道執行save()方法纔會保存到數據庫

e = Entry.objects.get(id=2)
e.blog = some_blog
e.save()

如果ForeignKey 設置了null=True 你可以賦值爲None

複製代碼
e = Entry.objects.get(id=2)
print e.blog # Hits the database to retrieve the associated Blog.
print e.blog # 不會在向數據庫取; 使用緩存中的值.

e = Entry.objects.select_related().get(id=2)
print e.blog # 不會在向數據庫取; 使用緩存中的值.
print e.blog # 不會在向數據庫取; 使用緩存中的值.

b = Blog.objects.get(id=1)
b.entry_set.all() # 返回所有blog的關聯對象.

# b.entry_set is a Manager that returns QuerySets.
b.entry_set.filter(headline__contains='Lennon')
b.entry_set.count()


b = Blog.objects.get(id=1)
b.entries.all() # 返回所有blog的關聯對象

# b.entries is a Manager that returns QuerySets.
b.entries.filter(headline__contains='Lennon')
b.entries.count()
複製代碼

 

add(obj1, obj2, ...) 增加多個關係對象
create(**kwargs) 建立新對象
remove(obj1, obj2, ...) 去除多個關係對象
clear() 清理所有關係對象

b = Blog.objects.get(id=1)
b.entry_set = [e1, e2]


1.3.4 Many-to-many關係

複製代碼
e = Entry.objects.get(id=3)
e.authors.all() # 返回Entry所有authors .
e.authors.count()
e.authors.filter(name__contains='John')

a = Author.objects.get(id=5)
a.entry_set.all() # 返回Author所有entry .
複製代碼


1.3.5 One-to-one關係

class EntryDetail(models.Model):
    entry = models.OneToOneField(Entry)
    details = models.TextField()

ed = EntryDetail.objects.get(id=2)
ed.entry # 返回 Entry 對象.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章