Django之ORM之QuerySet API

<1>all():         查詢所有結果
<2>filter(**kwargs)    它包含了與所給篩選條件相匹配的對象
<3>get(**kwargs):     返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
<4>exclude(**kwargs)    它包含了與所給篩選條件不匹配的對象
<5>values(*field)     返回一個ValueQuerySet 一個特殊的QuerySet,運行後得到的並不是一系列model的實例化對象,而是一個可迭代的字典序列
<6>values_list(*field)   它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列
<7>order_by(*field)    對查詢結果排序
<8>reverse()        對查詢結果反向排序
<9>distinct()       從返回結果中剔除重複紀錄
<10>count()        返回數據庫中匹配查詢(QuerySet)的對象數量。
<11>first()        返回第一條記錄
<12>last()         返回最後一條記錄
<13>exists()        如果QuerySet包含數據,就返回True,否則返回False
<14>annotate()       使用聚合函數
<15>dates()        根據日期獲取查詢集
<16>datetimes()      根據時間獲取查詢集
<17>none()         創建空的查詢集
<18>union()        並集
<19>intersection()     交集
<21>difference()      差集
<22>select_related()    附帶查詢關聯對象
<23>prefetch_related()   預先查詢
<24>extra()        附加SQL查詢
<25>defer()        不加載指定字段
<26>only()         只加載指定的字段
<27>using()        選擇數據庫
<28>select_for_update()  鎖住選擇的對象,直到事務結束。
<29>raw()         接收一個原始的SQL查詢

1、檢索所有對象all()

使用all()方法,可以獲取某張表的所有記錄。返回當前QuerySet(或QuerySet子類)的副本。通常用於獲取全部QuerySet對象。

查詢出來的是一個QuerySet的對象。

2、用filter過濾對象

filter(**kwargs)
返回滿足查詢參數的對象集合。
查找的參數(**kwargs)應該滿足下文字段查找中的格式。多個參數之間是和AND的關係。

常用例子:

# 大於,>,對應SQL:select * from Article where id > 724
Article.objects.filter(id__gt=724)
# 大於等於,>=,對應SQL:select * from Article where id >= 724
Article.objects.filter(id__gte=724)
# 小於,<,對應SQL:select * from Article where id < 724
Article.objects.filter(id__lt=724)
# 小於等於,<=,對應SQL:select * from Article where id <= 724
Article.objects.filter(id__lte=724)
# 同時大於和小於, 1 < id < 10,對應SQL:select * from Article where id > 1 and id < 10
Article.objects.filter(id__gt=1, id__lt=10)
# 包含,in,對應SQL:select * from Article where id in (11,22,33)
Article.objects.filter(id__in=[11, 22, 33])
# 不包含,not in,對應SQL:select * from Article where id not in (11,22,33)
Article.objects.filter(pub_date__isnull=True)
# 不爲空:isnull=False,對應SQL:select * from Article where pub_date is not null
Article.objects.filter(pub_date__isnull=True)
# 匹配,like,大小寫敏感,對應SQL:select * from Article where name like '%sre%',SQL中大小寫不敏感
Article.objects.filter(name__contains="sre")
# 匹配,like,大小寫不敏感,對應SQL:select * from Article where name like '%sre%',SQL中大小寫不敏感
Article.objects.filter(name__icontains="sre")
# 範圍,between and,對應SQL:select * from Article where id between 3 and 8
Article.objects.filter(id__range=[3, 8])
# 以什麼開頭,大小寫敏感,對應SQL:select * from Article where name like 'sh%',SQL中大小寫不敏感
Article.objects.filter(name__startswith='sre')
# 以什麼開頭,大小寫不敏感,對應SQL:select * from Article where name like 'sh%',SQL中大小寫不敏感
Article.objects.filter(name__istartswith='sre')
# 以什麼結尾,大小寫敏感,對應SQL:select * from Article where name like '%sre',SQL中大小寫不敏感
Article.objects.filter(name__endswith='sre')
# 以什麼結尾,大小寫不敏感,對應SQL:select * from Article where name like '%sre',SQL中大小寫不敏感
Article.objects.filter(name__iendswith='sre')
# 排序,order by,正序,對應SQL:select * from Article where name = '關鍵詞' order by id
Article.objects.filter(name='關鍵詞').order_by('id')
# 多級排序,order by,先按name進行正序排列,如果name一致則再按照id倒敘排列
Article.objects.filter(name='關鍵詞').order_by('name','-id')
# 排序,order by,倒序,對應SQL:select * from Article where name = '關鍵詞' order by id desc
Article.objects.filter(name='關鍵詞').order_by('-id')

3.查詢單一對象 get

filter方法始終返回的是QuerySets,那怕只有一個對象符合過濾條件,返回的也是包含一個對象的QuerySets,這是一個集合類型對象,你可以簡單的理解爲Python列表,可迭代可循環可索引。
如果你確定你的檢索只會獲得一個對象,那麼你可以使用get()方法來直接返回這個對象。get返回與所給篩選條件相匹配的對象,返回結果有且只有一個,如果符合篩選條件的對象超過一個或者沒有都會拋出錯誤。

#查詢ID=1的文章
Article.objects.get(id=1)
#等同
Article.objects.get(pk=1)

4、查詢不匹配條件的對象 exclude

exclude(**kwargs)

返回一個新的QuerySet,它包含滿足給定的查找參數的對象。

查找的參數(**kwargs)應該滿足下文字段查找中的格式。多個參數通過AND連接,然後所有的內容放入NOT() 中。

下面的示例排除所有created_time晚於2018-7-15headline爲“Hello” 的記錄:

Article.objects.exclude(created_time__gt=datetime.date(2018,7,15), headline='Hello')

下面的示例排除所有pub_date晚於2005-1-3或者headline 爲“Hello” 的記錄:

Article.objects.exclude(created_time__gt=datetime.date(2018,7,15)).exclude(headline='Hello')

5、查詢返回一個字典 values

返回一個ValueQuerySet,一個特殊的QuerySet,運行後得到的並不是一系列model的實例化對象,而是一個可迭代的字典序列。每個字典表示一個對象,鍵對應於模型對象的屬性名稱。

例:

#values()與普通的模型對象比較:
def orm(requst):
    article = models.Article.objects.filter(title__startswith='增加')
    article_values = models.Article.objects.filter(title__startswith='增加').values()
    print(article)
    print('----------------------------------------------')
    print(article_values)
    return HttpResponse('orm')
    
#打印結果  
<QuerySet [<Article: 增加標題一>, <Article: 增加標題二>]>
----------------------------------------------
<QuerySet [
{'id': 4, 'title': '增加標題一', 'intro': '', 'category_id': 3, 'body': '增加內容一', 'user_id': 1},
{'id': 6, 'title': '增加標題二', 'intro': '測試增加標題二', 'category_id': 4, 'body': '增加內容二', 'user_id': 2}
 ]>
 
#更多用法:
#不指定字段會獲取所有字段的鍵和值
article_values_all = models.Article.objects.values()
#如果指定字段,每個字典將只包含指定的字段的鍵/值。
article_values_filter = models.Article.objects.values('id', 'title')

#values()方法還有關鍵字參數**expressions,這些參數將傳遞給annotate()註釋
from django.db.models.functions import Lower
article_values=models.Article.objects.values(標題=Lower('title'))
<QuerySet [{'標題': '增加標題一'}, {'標題': '我被修改了'}, {'標題': '增加標題二'}]>

#聚合應用,統計作者下的文章數量
from django.db.models import Count
article_values_annotate = models.Article.objects.values('user').annotate(數量=Count('title'))
<QuerySet [{'user': 1, '數量': 3}, {'user': 2, '數量': 2}]>

#如果你有一個字段category是一個ForeignKey,默認的category_id參數返回的字典中將有一個叫做category的鍵,
#因爲這是保存實際值的那個隱藏的模型屬性的名稱
#當調用category_id並傳遞字段的名稱,傳遞category或values()都可以,得到的結果是相同的。
#像這樣:
category=models.Article.objects.values('category')
category_id = models.Article.objects.values('category_id')
<QuerySet [{'category': 3}, {'category': 3}, {'category': 4}, {'category': 4}, {'category': 4}]>
<QuerySet [{'category_id': 3}, {'category_id': 3}, {'category_id': 4}, {'category_id': 4}, {'category_id': 4}]>

6、查詢返回一個元組 values_list

values_list(*fields, flat=False)
與values()類似,只是在迭代時返回的是元組而不是字典。每個元組包含傳遞給values_list()調用的相應字段或表達式的值,因此第一個項目是第一個字段等。

看例子:

from django.db.models.functions import Lower
values_list=models.Article.objects.values_list('id','title')
values_list_lower = models.Article.objects.values_list('id', Lower('title'))
<QuerySet [(3, 'virtualenv使用技巧大全'), (4, '增加標題一'), (5, '我被修改了'), (6, '增加標題二')]>
<QuerySet [(3, 'virtualenv使用技巧大全'), (4, '增加標題一'), (5, '我被修改了'), (6, '增加標題二')]>

如果只傳遞一個字段,還可以傳遞flat參數。 如果爲True,它表示返回的結果爲單個值而不是元組。 如下所示:

values_list=models.Article.objects.values_list('id').order_by('id')
values_list_flat = models.Article.objects.values_list('id', flat=True).order_by('id')
<QuerySet [(2,), (3,), (4,), (5,), (6,)]>
<QuerySet [2, 3, 4, 5, 6]>

如果有多個字段,傳遞flat將發生錯誤。

7、查詢返回一個元組 order_by

order_by(*fields)
默認情況下,根據模型的Meta類中的ordering屬性對QuerySet中的對象進行排序

article = models.Article.objects.filter(created_time__year=2018).order_by('-created_time', 'title')

上面的結果將按照created_time降序排序,然後再按照title升序排序。"-created_time"前面的負號表示降序順序。 升序是默認的。 要隨機排序,使用"?",如下所示:

article = models.Article.objects.order_by('?')

注:order_by('?')可能耗費資源且很慢,這取決於使用的數據庫。

若要按照另外一個模型中的字段排序,可以使用查詢關聯模型的語法。即通過字段的名稱後面跟兩個下劃線(__),再加上新模型中的字段的名稱,直到希望連接的模型。

article = models.Article.objects.order_by('category__name', 'title')

如果排序的字段與另外一個模型關聯,Django將使用關聯的模型的默認排序,或者如果沒有指定Meta.ordering將通過關聯的模型的主鍵排序。 例如,因爲Blog模型沒有指定默認的排序:

article = models.Article.objects.order_by('category')
#等於:
article = models.Article.objects.order_by('category__id')

如果Blog設置了ordering = ['name'],那麼第一個QuerySet將等同於:

article = models.Article.objects.order_by('category__name')

還可以通過調用表達式的desc()或者asc()方法:

article = models.Article.objects.order_by(Coalesce('summary', 'title').desc())

8、對查詢結果反向排序 reverse

反向排序QuerySet中返回的元素。 第二次調用reverse()將恢復到原有的排序。
如要獲取QuerySet中最後三個元素,可以這樣做:

my_queryset.reverse()[:3]

這與Python直接使用負索引有點不一樣。 Django不支持負索引,只能曲線救國。

9、從返回結果中剔除重複紀錄 distinct

distinct(*fields)
去除查詢結果中重複的行。
默認情況下,QuerySet不會去除重複的行。當查詢跨越多張表的數據時,QuerySet可能得到重複的結果,這時候可以使用distinct()進行去重。

10、返回數據庫中匹配查詢(QuerySet)的對象數量  count

返回一個整數,該整數表示數據庫中與QuerySet匹配的對象的數量。

例子:

#返回數據庫中的條目總數
article = models.Article.objects.count()
#返回標題中包含“增加”的條目數
article_filter = models.Article.objects.filter(title__contains='增加').count()

count()調用在幕後執行SELECT count(*),因此您應該始終使用count(),而不是將所有記錄加載到Python對象中,然後對結果調用len()(除非無論如何都需要將對象加載到內存中,在這種情況下,len()會更快)。
注意,如果您想要查詢一個QuerySet中的項目數量,並且正在從它檢索模型實例(例如,通過遍歷它),那麼使用len(QuerySet)可能會更高效,因爲它不會像count()那樣導致額外的數據庫查詢。

11、返回由queryset匹配的第一個對象 first()

返回由queryset匹配的第一個對象,如果沒有匹配的對象,則返回None。如果QuerySet沒有定義任何排序,那麼QuerySet將由主鍵自動排序。

 

例子:

p = models.Article.objects.order_by('title', 'created_time').first()
#文章的'上一頁'就是通過這個實現的
previous_blog = Article.objects.filter(created_time__gt=article_obj.created_time).first()

注意,first()是一種簡潔的寫法,下面的代碼示例與上面的示例等價:

try:
    p = models.Article.objects.order_by('title', 'created_time')[0]
except IndexError:
    p = None

12、返回最後一條記錄last()

與first()類似,它是返回queryset中的最後一個對象。

#文章下一頁
netx_blog = Article.objects.filter(created_time__lt=article_obj.created_time).last()

13、返回最後一條記錄exists()

如果QuerySet包含數據,就返回True,否則返回False   ---只判斷是否有記錄

 

如果 QuerySet 包含任何結果,則返回 True,否則返回 False。這儘可能以最簡單和最快的方式執行查詢,但它確實執行與普通 QuerySet 查詢幾乎相同的查詢。

exists() 對於與 QuerySet 中的對象成員資格以及 QuerySet 中的任何對象(特別是大型 QuerySet 的上下文)中存在的相關搜索都很有用。

查找具有唯一字段(例如 primary_key)的模型是否爲 QuerySet 的成員的最有效方法是:

entry = Entry.objects.get(pk=123) if some_queryset.filter(pk=entry.pk).exists():     print("Entry contained in queryset")

這將比以下要求更快,需要對整個查詢集進行評估和迭代:

if entry in some_queryset:    print("Entry contained in QuerySet")

查找查詢集是否包含任何項目:

if some_queryset.exists():     print("There is at least one object in some_queryset")

這將比以下更快:

if some_queryset:     print("There is at least one object in some_queryset")

...但不是很大程度上(因此需要大量查詢來提高效率)。

14、使用提供的聚合表達式查詢對象annotate()

函數原型annotate(*args, **kwargs),返回QuerySet。

表達式可以是簡單的值、對模型(或任何關聯模型)上的字段的引用或者聚合表達式(平均值、總和等)。

annotate()的每個參數都是一個annotation,它將添加到返回的QuerySet每個對象中。

關鍵字參數指定的Annotation將使用關鍵字作爲Annotation 的別名。 匿名參數的別名將基於聚合函數的名稱和模型的字段生成。 只有引用單個字段的聚合表達式纔可以使用匿名參數。 其它所有形式都必須用關鍵字參數。

例如,如果正在操作一個Blog列表,你可能想知道每個Blog有多少Entry:

>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))# The name of the first blog
>>> q[0].name'Blogasaurus'# The number of entries on the first blog
>>> q[0].entry__count
42

Blog模型本身沒有定義entry__count屬性,但是通過使用一個關鍵字參數來指定聚合函數,可以控制Annotation的名稱:

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
35

15、根據日期獲取查詢集dates()

dates(field, kind, order='ASC')

返回一個QuerySet,表示QuerySet內容中特定類型的所有可用日期的datetime.date對象列表。

field參數是模型的DateField的名稱。 kind參數應爲"year","month"或"day"。 結果列表中的每個datetime.date對象被截取爲給定的類型。

"year" 返回對應該field的所有不同年份值的列表。

"month"返回字段的所有不同年/月值的列表。

"day"返回字段的所有不同年/月/日值的列表。

order參數默認爲'ASC',或者'DESC'。 它指定如何排序結果。

例子:

>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]

16、根據時間獲取查詢集datetimes()

datetimes(field_name, kind, order='ASC', tzinfo=None)

返回QuerySet,爲datetime.datetime對象的列表,表示QuerySet內容中特定種類的所有可用日期。

field_name應爲模型的DateTimeField的名稱。

kind參數應爲"hour","minute","month","year","second"或"day"。

結果列表中的每個datetime.datetime對象被截取到給定的類型。

order參數默認爲'ASC',或者'DESC'。 它指定如何排序結果。

tzinfo參數定義在截取之前將數據時間轉換到的時區。

17、 創建空的查詢集none()

調用none()將創建一個不返回任何對象的查詢集,並且在訪問結果時不會執行任何查詢。

例子:

>>> Entry.objects.none()<QuerySet []
>>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)True

18、並集union()

union(*other_qs, all=False)

Django中的新功能1.11。也就是集合中並集的概念!

使用SQL的UNION運算符組合兩個或更多個QuerySet的結果。例如:

>>> qs1.union(qs2, qs3)

默認情況下,UNION操作符僅選擇不同的值。 要允許重複值,請使用all=True參數。

19、交集intersection()

intersection(*other_qs)

Django中的新功能1.11。也就是集合中交集的概念!

使用SQL的INTERSECT運算符返回兩個或更多個QuerySet的共有元素。例如:

>>> qs1.intersection(qs2, qs3)

21、差集difference()

difference(*other_qs)

Django中的新功能1.11。也就是集合中差集的概念!

使用SQL的EXCEPT運算符只保留QuerySet中的元素,但不保留其他QuerySet中的元素。例如:

>>> qs1.difference(qs2, qs3)

22、附帶查詢關聯對象select_related()

select_related(*fields)

沿着外鍵關係查詢關聯的對象的數據。這會生成一個複雜的查詢並引起性能的損耗,但是在以後使用外鍵關係時將不需要再次數據庫查詢。

下面的例子解釋了普通查詢和select_related()查詢的區別。 下面是一個標準的查詢:

# 訪問數據庫。
e = Entry.objects.get(id=5)
# 再次訪問數據庫以得到關聯的Blog對象。
b = e.blog

下面是一個select_related查詢:

# 訪問數據庫。
e = Entry.objects.select_related('blog').get(id=5)
# 不會訪問數據庫,因爲e.blog已經在前面的查詢中獲得了。
b = e.blog

select_related()可用於objects任何的查詢集:

from django.utils import timezone

# Find all the blogs with entries scheduled to be published in the future.
blogs = set()

for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'):
    # 沒有select_related(),下面的語句將爲每次循環迭代生成一個數據庫查詢,以獲得每個entry關聯的blog。
    blogs.add(e.blog)

filter()select_related()的順序不重要。 下面的查詢集是等同的:

Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())

可以沿着外鍵查詢。 如果有以下模型:

from django.db import modelsclass City(models.Model):
    # ...
    passclass Person(models.Model):
    # ...
    hometown = models.ForeignKey(
        City,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )class Book(models.Model):
    # ...
    author = models.ForeignKey(Person, on_delete=models.CASCADE)

調用Book.objects.select_related('author__hometown').get(id=4)將緩存相關的Person 和相關的City:

b = Book.objects.select_related('author__hometown').get(id=4)
p = b.author         # Doesn't hit the database.
c = p.hometown       # Doesn't hit the database.
b = Book.objects.get(id=4) # No select_related() in this example.
p = b.author         # Hits the database.
c = p.hometown       # Hits the database.

在傳遞給select_related()的字段中,可以使用任何ForeignKey和OneToOneField。

在傳遞給select_related的字段中,還可以反向引用OneToOneField。也就是說,可以回溯到定義OneToOneField 的字段。 此時,可以使用關聯對象字段的related_name,而不要指定字段的名稱。

23、預先查詢prefetch_related()

prefetch_related(*lookups)

在單個批處理中自動檢索每個指定查找的相關對象。

select_related類似,但是策略是完全不同的。

假設有這些模型:

from django.db import modelsclass Topping(models.Model):
    name = models.CharField(max_length=30)class Pizza(models.Model):
    name = models.CharField(max_length=50)
    toppings = models.ManyToManyField(Topping)

    def __str__(self):              # __unicode__ on Python 2
        return "%s (%s)" % (
            self.name,
            ", ".join(topping.name for topping in self.toppings.all()),
        )

並運行:

>>> Pizza.objects.all()
["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...

問題是每次QuerySet要求Pizza.objects.all()查詢數據庫,因此self.toppings.all()將在Pizza Pizza.__str__()中的每個項目的Toppings表上運行查詢。

可以使用prefetch_related減少爲只有兩個查詢:

>>> Pizza.objects.all().prefetch_related('toppings')

這意味着現在每次self.toppings.all()被調用,不會再去數據庫查找,而是在一個預取的QuerySet緩存中查找。

還可以使用正常連接語法來執行相關字段的相關字段。 假設在上面的例子中增加一個額外的模型:

class Restaurant(models.Model):
    pizzas = models.ManyToManyField(Pizza, related_name='restaurants')
    best_pizza = models.ForeignKey(Pizza, related_name='championed_by')

以下是合法的:

>>> Restaurant.objects.prefetch_related('pizzas__toppings')

這將預取所有屬於餐廳的比薩餅,和所有屬於那些比薩餅的配料。 這將導致總共3個查詢 - 一個用於餐館,一個用於比薩餅,一個用於配料。

>>> Restaurant.objects.prefetch_related('best_pizza__toppings')

這將獲取最好的比薩餅和每個餐廳最好的披薩的所有配料。 這將在3個表中查詢 - 一個爲餐廳,一個爲“最佳比薩餅”,一個爲一個爲配料。

當然,也可以使用best_pizza來獲取select_related關係,以將查詢數減少爲2:

>>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')

24、附加SQL查詢extra()

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

有些情況下,Django的查詢語法難以簡單的表達複雜的WHERE子句,對於這種情況,可以在extra()生成的SQL從句中注入新子句。使用這種方法作爲最後的手段,這是一箇舊的API,在將來的某個時候可能被棄用。僅當無法使用其他查詢方法表達查詢時才使用它。

例如:

>>> qs.extra(
...     select={'val': "select col from sometable where othercol = %s"},
...     select_params=(someparam,),
... )

相當於:

>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))

25、不加載指定字段defer()

defer(*fields)

在一些複雜的數據建模情況下,模型可能包含大量字段,其中一些可能包含大尺寸數據(例如文本字段),將它們轉換爲Python對象需要花費很大的代價。

當最初獲取數據時不知道是否需要這些特定字段的情況下,如果正在使用查詢集的結果,可以告訴Django不要從數據庫中檢索它們。

通過傳遞字段名稱到defer()實現不加載:

Entry.objects.defer("headline", "body")

具有延遲加載字段的查詢集仍將返回模型實例。

每個延遲字段將在你訪問該字段時從數據庫中檢索(每次只檢索一個,而不是一次檢索所有的延遲字段)。

可以多次調用defer()。 每個調用都向延遲集添加新字段:

# 延遲body和headline兩個字段。
Entry.objects.defer("body").filter(rating=5).defer("headline")

字段添加到延遲集的順序無關緊要。對已經延遲的字段名稱再次defer()沒有問題(該字段仍將被延遲)。

可以使用標準的雙下劃線符號來分隔關聯的字段,從而加載關聯模型中的字段:

Blog.objects.select_related().defer("entry__headline", "entry__body")

如果要清除延遲字段集,將None作爲參數傳遞到defer():

# 立即加載所有的字段。
my_queryset.defer(None)

defer()方法(及其兄弟,only())僅適用於高級用例,它們提供了數據加載的優化方法。

26、只加載指定的字段only()

only(*fields)

only()方法與defer()相反。

如果有一個模型幾乎所有的字段需要延遲,使用only()指定補充的字段集可以使代碼更簡單。

假設有一個包含字段biography、age和name的模型。 以下兩個查詢集是相同的,就延遲字段而言:

Person.objects.defer("age", "biography")
Person.objects.only("name")

每當你調用only()時,它將替換立即加載的字段集。因此,對only()的連續調用的結果是隻有最後一次調用的字段被考慮:

# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")

由於defer()以遞增方式動作(向延遲列表中添加字段),因此你可以結合only()和defer()調用:

# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")
# Final result loads headline and body immediately (only() replaces any
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")

當對具有延遲字段的實例調用save()時,僅保存加載的字段。

27、選擇數據庫using()

using(alias)

如果正在使用多個數據庫,這個方法用於指定在哪個數據庫上查詢QuerySet。方法的唯一參數是數據庫的別名,定義在DATABASES。

例如:

# queries the database with the 'default' alias.
>>> Entry.objects.all()
# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')

28、鎖住選擇的對象,直到事務結束。select_for_update() 
elect_for_update(nowait=False, skip_locked=False)

返回一個鎖住行直到事務結束的查詢集,如果數據庫支持,它將生成一個SELECT ... FOR UPDATE語句。

例如:

entries = Entry.objects.select_for_update().filter(author=request.user)

所有匹配的行將被鎖定,直到事務結束。這意味着可以通過鎖防止數據被其它事務修改。

一般情況下如果其他事務鎖定了相關行,那麼本查詢將被阻塞,直到鎖被釋放。使用select_for_update(nowait=True)將使查詢不阻塞。如果其它事務持有衝突的鎖,那麼查詢將引發DatabaseError異常。也可以使用select_for_update(skip_locked=True)忽略鎖定的行。nowait和skip_locked是互斥的。

目前,postgresql,oracle和mysql數據庫後端支持select_for_update()。但是,MySQL不支持nowait和skip_locked參數。

29、接收一個原始的SQL查詢raw()

raw(raw_query, params=None, translations=None)

接收一個原始的SQL查詢,執行它並返回一個django.db.models.query.RawQuerySet實例。

這個RawQuerySet實例可以迭代,就像普通的QuerySet一樣。

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