成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

django 1.8 官方文檔翻譯: 2-5-4 聚合

Tonny / 2914人閱讀

摘要:查詢集參考中列出了聚合函數(shù)的列表。鍵的名稱是按照字段和聚合函數(shù)的名稱自動(dòng)生成出來的。例如,要得到每個(gè)書店的價(jià)格區(qū)別,可以使用如下注解這段代碼告訴獲取書店模型,并連接通過多對多關(guān)系圖書模型,然后對每本書的價(jià)格進(jìn)行聚合,得出最小值和最大值。

  

Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。

交流群:467338606

網(wǎng)站:http://python.usyiyi.cn/django/index.html

聚合

Django數(shù)據(jù)庫抽象API描述了使用Django查詢來增刪查改單個(gè)對象的方法。然而,你有時(shí)候會(huì)想要獲取從一組對象導(dǎo)出的值或者是聚合一組對象。這份指南描述了通過Django查詢來生成和返回聚合值的方法。

整篇指南我們都將引用以下模型。這些模型用來記錄多個(gè)網(wǎng)上書店的庫存。

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()

class Publisher(models.Model):
    name = models.CharField(max_length=300)
    num_awards = models.IntegerField()

class Book(models.Model):
    name = models.CharField(max_length=300)
    pages = models.IntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)
    rating = models.FloatField()
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    pubdate = models.DateField()

class Store(models.Model):
    name = models.CharField(max_length=300)
    books = models.ManyToManyField(Book)
    registered_users = models.PositiveIntegerField()
速查表

急著用嗎?以下是在上述模型的基礎(chǔ)上,進(jìn)行一般的聚合查詢的方法:

# Total number of books.
>>> Book.objects.count()
2452

# Total number of books with publisher=BaloneyPress
>>> Book.objects.filter(publisher__name="BaloneyPress").count()
73

# Average price across all books.
>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg("price"))
{"price__avg": 34.35}

# Max price across all books.
>>> from django.db.models import Max
>>> Book.objects.all().aggregate(Max("price"))
{"price__max": Decimal("81.20")}

# Cost per page
>>> Book.objects.all().aggregate(
...    price_per_page=Sum(F("price")/F("pages"), output_field=FloatField()))
{"price_per_page": 0.4470664529184653}

# All the following queries involve traversing the Book<->Publisher
# many-to-many relationship backward

# Each publisher, each with a count of books as a "num_books" attribute.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count("book"))
>>> pubs
[, , ...]
>>> pubs[0].num_books
73

# The top 5 publishers, in order by number of books.
>>> pubs = Publisher.objects.annotate(num_books=Count("book")).order_by("-num_books")[:5]
>>> pubs[0].num_books
1323
在查詢集上生成聚合

Django提供了兩種生成聚合的方法。第一種方法是從整個(gè)查詢集生成統(tǒng)計(jì)值。比如,你想要計(jì)算所有在售書的平均價(jià)錢。Django的查詢語法提供了一種方式描述所有圖書的集合。

>>> Book.objects.all()

我們需要在QuerySet.對象上計(jì)算出總價(jià)格。這可以通過在QuerySet后面附加aggregate() 子句來完成。

>>> from django.db.models import Avg
>>> Book.objects.all().aggregate(Avg("price"))
{"price__avg": 34.35}

all()在這里是多余的,所以可以簡化為:

>>> Book.objects.aggregate(Avg("price"))
{"price__avg": 34.35}

aggregate()子句的參數(shù)描述了我們想要計(jì)算的聚合值,在這個(gè)例子中,是Book 模型中price字段的平均值。查詢集參考中列出了聚合函數(shù)的列表。

aggregate()是QuerySet 的一個(gè)終止子句,意思是說,它返回一個(gè)包含一些鍵值對的字典。鍵的名稱是聚合值的標(biāo)識符,值是計(jì)算出來的聚合值。鍵的名稱是按照字段和聚合函數(shù)的名稱自動(dòng)生成出來的。如果你想要為聚合值指定一個(gè)名稱,可以向聚合子句提供它。

>>> Book.objects.aggregate(average_price=Avg("price"))
{"average_price": 34.35}

如果你希望生成不止一個(gè)聚合,你可以向aggregate()子句中添加另一個(gè)參數(shù)。所以,如果你也想知道所有圖書價(jià)格的最大值和最小值,可以這樣查詢:

>>> from django.db.models import Avg, Max, Min
>>> Book.objects.aggregate(Avg("price"), Max("price"), Min("price"))
{"price__avg": 34.35, "price__max": Decimal("81.20"), "price__min": Decimal("12.99")}
為查詢集的每一項(xiàng)生成聚合

生成匯總值的第二種方法,是為QuerySet中每一個(gè)對象都生成一個(gè)獨(dú)立的匯總值。比如,如果你在檢索一列圖書,你可能想知道有多少作者寫了每一本書。每本書和作者是多對多的關(guān)系。我們想要匯總QuerySet.中每本書里的這種關(guān)系。

逐個(gè)對象的匯總結(jié)果可以由annotate()子句生成。當(dāng)annotate()子句被指定之后,QuerySet中的每個(gè)對象都會(huì)被注上特定的值。

這些注解的語法都和aggregate()子句所使用的相同。annotate()的每個(gè)參數(shù)都描述了將要被計(jì)算的聚合。比如,給圖書添加作者數(shù)量的注解:

# Build an annotated queryset
>>> from django.db.models import Count
>>> q = Book.objects.annotate(Count("authors"))
# Interrogate the first object in the queryset
>>> q[0]

>>> q[0].authors__count
2
# Interrogate the second object in the queryset
>>> q[1]

>>> q[1].authors__count
1

和使用 aggregate()一樣,注解的名稱也根據(jù)聚合函式的名稱和聚合字段的名稱得到的。你可以在指定注解時(shí),為默認(rèn)名稱提供一個(gè)別名:

>>> q = Book.objects.annotate(num_authors=Count("authors"))
>>> q[0].num_authors
2
>>> q[1].num_authors
1

與 aggregate() 不同的是, annotate() 不是一個(gè)終止子句。annotate()子句的返回結(jié)果是一個(gè)查詢集 (QuerySet);這個(gè) QuerySet可以用任何QuerySet方法進(jìn)行修改,包括 filter(), order_by(), 甚至是再次應(yīng)用annotate()。

  

有任何疑問的話,請檢查 SQL query!

要想弄清楚你的查詢到底發(fā)生了什么,可以考慮檢查你QuerySet的 query 屬性。

例如,在annotate() 中混入多個(gè)聚合將會(huì)得出錯(cuò)誤的結(jié)果,因?yàn)槎鄠€(gè)表上做了交叉連接,導(dǎo)致了多余的行聚合。

連接和聚合

至此,我們已經(jīng)了解了作用于單種模型實(shí)例的聚合操作, 但是有時(shí),你也想對所查詢對象的關(guān)聯(lián)對象進(jìn)行聚合。

在聚合函式中指定聚合字段時(shí),Django 允許你使用同樣的 雙下劃線 表示關(guān)聯(lián)關(guān)系,然后 Django 在就會(huì)處理要讀取的關(guān)聯(lián)表,并得到關(guān)聯(lián)對象的聚合。

例如,要得到每個(gè)書店的價(jià)格區(qū)別,可以使用如下注解:

>>> from django.db.models import Max, Min
>>> Store.objects.annotate(min_price=Min("books__price"), max_price=Max("books__price"))

這段代碼告訴 Django 獲取書店模型,并連接(通過多對多關(guān)系)圖書模型,然后對每本書的價(jià)格進(jìn)行聚合,得出最小值和最大值。

同樣的規(guī)則也用于 aggregate() 子句。如果你想知道所有書店中最便宜的書和最貴的書價(jià)格分別是多少:

>>> Store.objects.aggregate(min_price=Min("books__price"), max_price=Max("books__price"))

關(guān)系鏈可以按你的要求一直延伸。 例如,想得到所有作者當(dāng)中最小的年齡是多少,就可以這樣寫:

>>> Store.objects.aggregate(youngest_age=Min("books__authors__age"))
遵循反向關(guān)系

和 跨關(guān)系查找的方法類似,作用在你所查詢的模型的關(guān)聯(lián)模型或者字段上的聚合和注解可以遍歷"反轉(zhuǎn)"關(guān)系。關(guān)聯(lián)模型的小寫名稱和雙下劃線也用在這里。

例如,我們可以查詢所有出版商,并注上它們一共出了多少本書(注意我們?nèi)绾斡?"book"指定Publisher -> Book 的外鍵反轉(zhuǎn)關(guān)系):

>>> from django.db.models import Count, Min, Sum, Avg
>>> Publisher.objects.annotate(Count("book"))

QuerySet結(jié)果中的每一個(gè)Publisher都會(huì)包含一個(gè)額外的屬性叫做book__count。

我們也可以按照每個(gè)出版商,查詢所有圖書中最舊的那本:

>>> Publisher.objects.aggregate(oldest_pubdate=Min("book__pubdate"))

(返回的字典會(huì)包含一個(gè)鍵叫做 "oldest_pubdate"。如果沒有指定這樣的別名,它會(huì)更長一些,像 "book__pubdate__min"。)

這不僅僅可以應(yīng)用掛在外鍵上面。還可以用到多對多關(guān)系上。例如,我們可以查詢每個(gè)作者,注上它寫的所有書(以及合著的書)一共有多少頁(注意我們?nèi)绾问褂?"book"來指定Author -> Book的多對多的反轉(zhuǎn)關(guān)系):

>>> Author.objects.annotate(total_pages=Sum("book__pages"))

(每個(gè)返回的QuerySet中的Author 都有一個(gè)額外的屬性叫做total_pages。如果沒有指定這樣的別名,它會(huì)更長一些,像 book__pages__sum。)

或者查詢所有圖書的平均評分,這些圖書由我們存檔過的作者所寫:

>>> Author.objects.aggregate(average_rating=Avg("book__rating"))

(返回的字典會(huì)包含一個(gè)鍵叫做"average__rating"。如果沒有指定這樣的別名,它會(huì)更長一些,像"book__rating__avg"。)

聚合和其他查詢集子句

filter() 和 exclude()

聚合也可以在過濾器中使用。 作用于普通模型字段的任何 filter()(或 exclude()) 都會(huì)對聚合涉及的對象進(jìn)行限制。

使用annotate() 子句時(shí),過濾器有限制注解對象的作用。例如,你想得到以 "Django" 為書名開頭的圖書作者的總數(shù):

>>> from django.db.models import Count, Avg
>>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count("authors"))

使用aggregate()子句時(shí),過濾器有限制聚合對象的作用。例如,你可以算出所有以 "Django" 為書名開頭的圖書平均價(jià)格:

>>> Book.objects.filter(name__startswith="Django").aggregate(Avg("price"))
對注解過濾

注解值也可以被過濾。 像使用其他模型字段一樣,注解也可以在filter()和exclude() 子句中使用別名。

例如,要得到不止一個(gè)作者的圖書,可以用:

>>> Book.objects.annotate(num_authors=Count("authors")).filter(num_authors__gt=1)

這個(gè)查詢首先生成一個(gè)注解結(jié)果,然后再生成一個(gè)作用于注解上的過濾器。

annotate() 的順序

編寫一個(gè)包含 annotate() 和 filter() 子句的復(fù)雜查詢時(shí),要特別注意作用于 QuerySet的子句的順序。

當(dāng)一個(gè)annotate() 子句作用于某個(gè)查詢時(shí),要根據(jù)查詢的狀態(tài)才能得出注解值,而狀態(tài)由 annotate() 位置所決定。以這就導(dǎo)致filter() 和 annotate() 不能交換順序,下面兩個(gè)查詢就是不同的:

>>> Publisher.objects.annotate(num_books=Count("book")).filter(book__rating__gt=3.0)

另一個(gè)查詢:

>>> Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count("book"))

兩個(gè)查詢都返回了至少出版了一本好書(評分大于 3 分)的出版商。 但是第一個(gè)查詢的注解包含其該出版商發(fā)行的所有圖書的總數(shù);而第二個(gè)查詢的注解只包含出版過好書的出版商的所發(fā)行的圖書總數(shù)。 在第一個(gè)查詢中,注解在過濾器之前,所以過濾器對注解沒有影響。 在第二個(gè)查詢中,過濾器在注解之前,所以,在計(jì)算注解值時(shí),過濾器就限制了參與運(yùn)算的對象的范圍。

order_by()

注解可以用來做為排序項(xiàng)。 在你定義 order_by() 子句時(shí),你提供的聚合可以引用定義的任何別名做為查詢中 annotate()子句的一部分。

例如,根據(jù)一本圖書作者數(shù)量的多少對查詢集 QuerySet進(jìn)行排序:

>>> Book.objects.annotate(num_authors=Count("authors")).order_by("num_authors")
values()

通常,注解會(huì)添加到每個(gè)對象上 —— 一個(gè)被注解的QuerySet會(huì)為初始QuerySet的每個(gè)對象返回一個(gè)結(jié)果集。但是,如果使用了values()子句,它就會(huì)限制結(jié)果中列的范圍,對注解賦值的方法就會(huì)完全不同。不是在原始的 QuerySet返回結(jié)果中對每個(gè)對象中添加注解,而是根據(jù)定義在values() 子句中的字段組合對先結(jié)果進(jìn)行唯一的分組,再根據(jù)每個(gè)分組算出注解值, 這個(gè)注解值是根據(jù)分組中所有的成員計(jì)算而得的:

例如,考慮一個(gè)關(guān)于作者的查詢,查詢出每個(gè)作者所寫的書的平均評分:

>>> Author.objects.annotate(average_rating=Avg("book__rating"))

這段代碼返回的是數(shù)據(jù)庫中所有的作者以及他們所著圖書的平均評分。

但是如果你使用了values()子句,結(jié)果是完全不同的:

>>> Author.objects.values("name").annotate(average_rating=Avg("book__rating"))

在這個(gè)例子中,作者會(huì)按名稱分組,所以你只能得到某個(gè)唯一的作者分組的注解值。 這意味著如果你有兩個(gè)作者同名,那么他們原本各自的查詢結(jié)果將被合并到同一個(gè)結(jié)果中;兩個(gè)作者的所有評分都將被計(jì)算為一個(gè)平均分。

annotate() 的順序

和使用 filter() 子句一樣,作用于某個(gè)查詢的annotate() 和 values() 子句的使用順序是非常重要的。如果values() 子句在 annotate() 之前,就會(huì)根據(jù) values() 子句產(chǎn)生的分組來計(jì)算注解。

但是,如果 annotate() 子句在 values()子句之前,就會(huì)根據(jù)整個(gè)查詢集生成注解。在這種情況下,values() 子句只能限制輸出的字段范圍。

舉個(gè)例子,如果我們互換了上個(gè)例子中 values()和 annotate() 子句的順序:

>>> Author.objects.annotate(average_rating=Avg("book__rating")).values("name", "average_rating")

這段代碼將給每個(gè)作者添加一個(gè)唯一的字段,但只有作者名稱和average_rating 注解會(huì)返回在輸出結(jié)果中。

你也應(yīng)該注意到 average_rating 顯式地包含在返回的列表當(dāng)中。之所以這么做的原因正是因?yàn)関alues() 和 annotate() 子句。

如果 values() 子句在 annotate() 子句之前,注解會(huì)被自動(dòng)添加到結(jié)果集中;但是,如果 values() 子句作用于annotate() 子句之后,你需要顯式地包含聚合列。

與默認(rèn)排序或order_by()交互

在查詢集中的order_by() 部分(或是在模型中默認(rèn)定義的排序項(xiàng)) 會(huì)在選擇輸出數(shù)據(jù)時(shí)被用到,即使這些字段沒有在values() 調(diào)用中被指定。這些額外的字段可以將相似的數(shù)據(jù)行分在一起,也可以讓相同的數(shù)據(jù)行相分離。在做計(jì)數(shù)時(shí),就會(huì)表現(xiàn)地格外明顯:

通過例子中的方法,假設(shè)有一個(gè)這樣的模型:

from django.db import models

class Item(models.Model):
    name = models.CharField(max_length=10)
    data = models.IntegerField()

    class Meta:
        ordering = ["name"]

關(guān)鍵的部分就是在模型默認(rèn)排序項(xiàng)中設(shè)置的name字段。如果你想知道每個(gè)非重復(fù)的data值出現(xiàn)的次數(shù),可以這樣寫:

# Warning: not quite correct!
Item.objects.values("data").annotate(Count("id"))

...這部分代碼想通過使用它們公共的 data 值來分組 Item對象,然后在每個(gè)分組中得到 id 值的總數(shù)。但是上面那樣做是行不通的。這是因?yàn)槟J(rèn)排序項(xiàng)中的 name也是一個(gè)分組項(xiàng),所以這個(gè)查詢會(huì)根據(jù)非重復(fù)的 (data, name) 進(jìn)行分組,而這并不是你本來想要的結(jié)果。所以,你應(yīng)該這樣改寫:

Item.objects.values("data").annotate(Count("id")).order_by()

...這樣就清空了查詢中的所有排序項(xiàng)。 你也可以在其中使用 data ,這樣并不會(huì)有副作用,這是因?yàn)椴樵兎纸M中只有這么一個(gè)角色了。

這個(gè)行為與查詢集文檔中提到的 distinct() 一樣,而且生成規(guī)則也一樣:一般情況下,你不想在結(jié)果中由額外的字段扮演這個(gè)角色,那就清空排序項(xiàng),或是至少保證它僅能訪問 values()中的字段。

  

注意

你可能想知道為什么 Django 不刪除與你無關(guān)的列。主要原因就是要保證使用 distinct()和其他方法的一致性。Django 永遠(yuǎn)不會(huì) 刪除你所指定的排序限制(我們不能改動(dòng)那些方法的行為,因?yàn)檫@會(huì)違背 API stability 原則)。

聚合注解

你也可以在注解的結(jié)果上生成聚合。 當(dāng)你定義一個(gè) aggregate() 子句時(shí),你提供的聚合會(huì)引用定義的任何別名做為查詢中 annotate() 子句的一部分。

例如,如果你想計(jì)算每本書平均有幾個(gè)作者,你先用作者總數(shù)注解圖書集,然后再聚合作者總數(shù),引入注解字段:

>>> from django.db.models import Count, Avg
>>> Book.objects.annotate(num_authors=Count("authors")).aggregate(Avg("num_authors"))
{"num_authors__avg": 1.66}

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/17478.html

相關(guān)文章

  • django 1.8 官方文檔翻譯2-6-4 數(shù)據(jù)庫訪問優(yōu)化

    摘要:文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。交流群網(wǎng)站數(shù)據(jù)庫訪問優(yōu)化的數(shù)據(jù)庫層提供了很多方法來幫助開發(fā)者充分的利用他們的數(shù)據(jù)庫。使用標(biāo)準(zhǔn)數(shù)據(jù)庫優(yōu)化技巧包括索引。整體插入創(chuàng)建對象時(shí),盡可能使用來減少查詢的數(shù)量。 Django 文檔協(xié)作翻譯小組人手緊缺,有興趣的朋友可以加入我們,完全公益性質(zhì)。 交流群:467338606 網(wǎng)站:http://...

    Simon 評論0 收藏0
  • django 中文文檔協(xié)作翻譯尋求翻譯小能手

    摘要:是的一個(gè)框架,因?yàn)榫W(wǎng)上目前沒有完整的中文文檔,就和幾個(gè)志同道合的朋友建了協(xié)作翻譯網(wǎng)站,來翻譯官方文檔,完全公益性質(zhì),有興趣的朋友可以加入我們,菜鳥也可以,揀會(huì)的翻譯,就當(dāng)練練手。而且很方便,在網(wǎng)頁可直接提交翻譯。 django是Python的一個(gè)web框架,因?yàn)榫W(wǎng)上目前沒有完整的中文文檔,就和幾個(gè)志同道合的朋友建了協(xié)作翻譯網(wǎng)站,來翻譯官方文檔,完全公益性質(zhì),有興趣的朋友可以加入我們,菜...

    rollback 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<