Django ORM查询之外键、关系的反向引用
關系本身就是相互的,只用在一個表中記錄,而不是在有關系的兩個表中都記錄。所以外鍵、關系提供反向引用機制。當然,外鍵可以是多個表的外鍵,關系也可以與多個表有關系,所以反向引用必須顯式指出關系對方表(然后是字段)。而正向引用則不必,因為正向引用在定義時就指定了關系對方表(Book::publisher = ForeignKey(‘Publisher’)、Book::authors = ManyToManyField(‘Author’) )
Joins and aggregates關系連接和集合函數
So far, we have dealt with aggregates over fields that belong to the model being queried. However, sometimes the value you want to aggregate will belong to a model that is related to the model you are querying.
到目前為止,我們已經在被查詢的模型的字段上處理了集合操作。然而,有時候你想要求集合的值屬于你查詢的模型的關聯的模型。
When specifying the field to be aggregated in an aggregate function, Django will allow you to use the same double underscore notation that is used when referring to related fields in filters. Django will then handle any table joins that are required to retrieve and aggregate the related value.
當在一個集合函數中指定要集合的字段,Django將允許你像在filters中引用關聯字段時那樣使用兩下劃線符號。Django之后將處理任何請求的表的連接,以便檢索并集合關聯的值。
For example, to find the price range of books offered in each store, you could use the annotation:
例如,要找到每家書店提供的書的單價范圍,你可以使用注釋:
#~~~~~~~
>>> from django.db.models import Max, Min
>>> Store.objects.annotate( min_price=Min('books__price'), max_price=Max('books__price') )
#對Store中單個記錄,按一對多關系連接books表,對一對多的所有books的price字段進行集集合算Min()、Max()
#~~~~~~~
This tells Django to retrieve the Store model, join (through the many-to-many relationship) with the Book model, and aggregate on the price field of the book model to produce a minimum and maximum value.
這告訴Django檢索Store模型,連接(通過多對多關系)Book模型,集合book模型的單價字段來生成最低和最高值。
Store模型:
| id | name | books,存儲售賣的所有書,多對多關系 |
Book模型:
| id | name | authors,存儲所有為本書貢獻了的作者,多對多關系 | price |
Author模型:
| id | name | age |
?
關系就是要來告訴數據庫去連接的。
The same rules apply to the aggregate() clause. If you wanted to know the lowest and highest price of any book that is available for sale in any of the stores, you could use the aggregate:
同樣的規則也應用于集合aggregate()子句。
#~~~~~~
>>> Store.objects.aggregate( min_price=Min('books__price'), max_price=Max('books__price') )
#Store模型的books關系字段__關系連接的Book模型的price字段
#~~~~~~
Join chains can be as deep as you require. For example, to extract the age of the youngest author of any book available for sale, you could issue the query:
連接鏈可以如你所需要的深度那么深。例如,提取售賣的任意書的最年輕的作者的年齡,你可以這樣處理查詢:
#~~~~~~~~~
Store.objects.aggregate( yongest_author_age = Min(‘books__authors__age’) )
#Store模型的books關系字段__連接的Book模型的authors關系字段__連接的Author模型的age字段
#~~~~~~~~~
?
Following relationships backwards
In a way similar to Lookups that span relationships, aggregations and annotations on fields of models or models that are related to the one you are querying can include traversing “reverse” relationships. The lowercase name of related models and double-underscores are used here too.
以類似于跨關系查找的方式,在模型或關聯到你正在查詢的模型的模型的字段上進行集合和注釋可以包括遍歷”反向”關系。這里也用到了關聯模型的名字的小寫與兩下劃線。
Store模型:
| id | name | books,存儲售賣的所有書,多對多關系 |
Book模型:
| id | name | authors,存儲所有為本書貢獻樂的作者,多對多關系,多值字段 | pubdate | rating | pages | publisher,外鍵,數據庫中存儲所引用的外鍵的主鍵,可以多對一關系Publisher模型記錄 | price |
關系本身就是相互的,只用在一個表中記錄,而不是在有關系的兩個表中都記錄。所以外鍵、關系提供反向引用機制。當然,外鍵可以是多個表的外鍵,關系也可以與多個表有關系,所以反向引用必須顯式指出關系對方表(然后是字段)。而正向引用則不必,因為正向引用在定義時就指定了關系對方表(Book::publisher = ForeignKey(‘Publisher’)、Book::authors = ManyToManyField(‘Author’) )
Author模型:
| id | name | age |
Publisher模型:
| id,主鍵,作為Book模型publisher字段的外鍵,可以一對多關系Book模型記錄 | name |
?
For example, we can ask for all publishers, annotated with their respective total book stock counters (note how we use 'book' to specify the Publisher -> Book reverse foreign key hop):
例如,我們可以請求所有出版商,對他們對應的總同屬存貨計數(注意我們如何使用’book’指定Publisher ->Book反向外鍵跳躍):
#~~~~~~
>>> from django.db.models import Avg, Count, Min, Sum
>>> Publisher.objects.annotate( Count('book') )
#’book’——Publisher被外鍵引用的Book模型,對反向外鍵關系的Book模型的所有記錄計數,反向外鍵引用必須顯式指定反向外鍵引用的表book,統計的話不用再加字段) )
#~~~~~~
(Every Publisher in the resulting QuerySet will have an extra attribute called book__count.)
結果查詢集中的每個Publisher將具有一個特殊的屬性(注釋列,只存在于返回的查詢集上)稱作book__count。
We can also ask for the oldest book of any of those managed by every publisher:
我們也可以請求每個出版商管理的書籍中最老的書(Book模型的publisher外鍵引用Poblish模型,為此Poblisher模型需要反向外鍵引用Book模型):
#~~~~~~~~~
我想的:Publisher.objects.annotate( oldest_book = Min(‘book__pubdate’) )
#為Publisher模型的每個記錄注釋一個’oldest_book’,是對反向外鍵關系Book模型的pubdate最小的那個book實例,反向外鍵引用必須顯式指定反向外鍵引用的表book,再加其一個字段。
>>> Publisher.objects.aggregate(oldest_pubdate=Min('book__pubdate'))
#官檔為Publisher模型的每個記錄返回一個包含名字’oldest_pubdate’的字典,值就是反向關系(一個Publisher對應多個Book的)
#~~~~~~~~~~
返回的結果字典將有一個稱作’oldest_pubdate’的鍵。如果不指定別名,將會是很長的’book__pubdate_min’(包含引用鏈的字段名__集合類名(集合函數名) )。
This doesn’t apply just to foreign keys. It also works with many-to-many relations. For example, we can ask for every author, annotated with the total number of pages considering all the books the author has (co-)authored (note how we use 'book' to specify the Author -> Book reverse many-to-many hop):
反向引用不僅能應用到外鍵,還可以應用到多對多關系。例如,我們可以請求每個作者,注釋該作者參與編輯的所有書的總頁數(注意我們是如何使用’boo’去指定Author -> Book反向多對多跳躍的):
#~~~~~~~~~~
>>> Author.objects.annotate( total_pages=Sum('book__pages') )
#外鍵和關系都可以被反向引用,反向引用時必須顯式指出反向引用的表名的小寫,book。這里將Book模型的author多對多關系Author模型進行了反向,Author模型反向多對多關系Book模型的pages字段
#~~~~~~~~~~
結果查詢集中的每個Author將會具有一個額外的屬性稱作total_pages。如果不指定這樣的別名,將會是很長的’book__pages__sum)。
?
Or ask for the average rating of all the books written by author(s) we have on file:
或者請求我們在文件中存在的作者所寫的所有書的平均評分:
#~~~~~~~~~~
Author.objects.annotate( avg_rating = Avg(‘book__rating’) )
或
Author.objects.aggregate( avg_rating = Avg(‘book__rating’) )
#~~~~~~~~~~
結果字典將具有一個稱作’avg__rating’的鍵。如果不指定這樣一個別名,將會是挺長的’book__rating__avg’。
?
Aggregations and other QuerySet clauses
filter() and exclude()
Aggregates can also participate in filters. Any filter() (or exclude()) applied to normal model fields will have the effect of constraining the objects that are considered for aggregation.
集合也可以參與到filters中。任何應用到正常模型字段上的filter()或exclude()將具有約束考慮使用集合aggregation的對象的作用。
When used with an annotate() clause, a filter has the effect of constraining the objects for which an annotation is calculated. For example, you can generate an annotated list of all books that have a title starting with “Django” using the query:
當與一個annotate()子句一起使用時,過濾器具有約束為其計算注釋的對象的作用。例如,使用查詢,你可以為標題以’Django’開頭的所有書籍生成一個注釋列。
#~~~~~~~
>>> from django.db.models import Avg, Count
>>> Book.objects.filter( name__startswith="Django" ).annotate( num_authors=Count('authors') )
#過濾返回一個查詢集,總是可以為查詢集增加注釋列
#~~~~~~~
When used with an aggregate() clause, a filter has the effect of constraining the objects over which the aggregate is calculated. For example, you can generate the average price of all books with a title that starts with “Django” using the query:
當與一個集合aggregate()子句一起使用,過濾器具有約束為其計算集合的對象的作用。例如,使用查詢,你可以為標題以’Django’開頭的所有書籍生成平均單價。
#~~~~~~~~
Book.objects.filter( name__startswith=’Django’ ).aggregate( avg_price = Avg(price) )
#這里既然Book記錄的price是一個single值,則Avg(price)是對查詢集所有記錄的price求均值。并返回單個字典avg_price:值。像下面:
#~~~~~~~
#~~~~~~~~
>>> from django.db.models import Avg, Max, Min
>>> Book.objects.aggregate( Avg('price'), Max('price'), Min('price') ) #Manager::aggregate()對全集計算集合意味的值,返回這些值的字典
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
#因為Book記錄的price是一個FloatField()值字段,所以Avg(‘price’)、Max(‘price’)、Min(‘price’)是對查詢集所有記錄的price進行集合處理。并返回單個字典
#~~~~~~~~
#~~~~~~
>>> q = Book.objects.annotate( num_authors=Count('authors') )
>>> q[0].num_authors
2
>>> q[1].num_authors
1
#因為Book記錄的authors是MantToManyField多對多字段,所以Count(‘authors’)是對Book記錄的一對多authors字段的集合aggregate處理,對每個Book記錄返回各自的注釋列。
#~~~~~~
Filtering on annotations
Annotated values can also be filtered. The alias for the annotation can be used in filter() and exclude() clauses in the same way as any other model field.
被注釋的值也可以被過濾。注釋列的別名可以用在filter()和exclude()子句中,以與其他模型字段相同的方式。
For example, to generate a list of books that have more than one author, you can issue the query:
例如,生成具有兩位及以上作者的書的列表,你可以這樣處理查詢:
#~~~~~~~~~
Books.objects.annotate( num_authors = Count(‘authors’) ).filter( num_authors__gte=2 )
Books.objects.annotate( num_authors = ExpressionWrapper( Count(‘authors’), output_field = IntegerField())?).filter( num_authors__gte=2 )
#~~~~~~~~
This query generates an annotated result set, and then generates a filter based upon that annotation.
這個查詢集生成一個注釋后的結果查詢集,然后基于這個注釋后的查詢集生成一個過濾后的查詢集。
If you need two annotations with two separate filters you can use the filter argument with any aggregate. For example, to generate a list of authors with a count of highly rated books:
如果你需要兩個注釋,使用兩個單獨的過濾,你可以使用filter參數在任意繼承中。例如,生成authors的一個列表,帶每個作者較高評分(7星及以上的)的著作的計數:
#~~~~~~~~
>>> highly_rated = Count( 'book', filter=Q(book__rating__gte=7) )
>>> Author.objects.annotate( num_books=Count('book'), highly_rated_books=highly_rated )
#num_books是每個Author實例的著作數(反向關系'book'+Count集合),highly_rated_books是每個Author的著作中評分大于等于7分的著作計數(反向關系'book'+過濾+Count集合,封裝查詢條件的Q實例對象要放在其他實參’book’后面)
#上面Count()是構造的models.Count類實例對象,不是Manager類或QuerySet類的count()實例方法。
Help on class Count in module django.db.models.aggregates:
?
class Count(Aggregate)
?| ?Count(*args, **kwargs)
?| ?
?| ?An SQL function call.
?| ?
?| ?Method resolution order:
?| ?????Count
?| ?????Aggregate
?| ?????django.db.models.expressions.Func
?| ?????django.db.models.expressions.SQLiteNumericMixin
?| ?????django.db.models.expressions.Expression
?| ?????django.db.models.expressions.BaseExpression
?| ?????django.db.models.expressions.Combinable
?| ?????builtins.object
?| ?
?| ?Methods defined here:
?| ?
?| ?__init__(self, expression, filter=None, **extra)?#expression可以是要集合操作的字段,filter是查詢子句
?| ?????Initialize self. ?See help(type(self)) for accurate signature.
#~~~~~~~~
| Choosing between filter and QuerySet.filter()在filter(Aggregate)類與QuerySet.filter()實例方法之前選擇 ? Avoid using the filter argument with a single annotation or aggregation. It’s more efficient to use QuerySet.filter() to exclude rows. The aggregation filter argument is only useful when using two or more aggregations over the same relations with different conditionals. 避免在單個注釋annotation或集合aggregation中使用filter參數(下上面Count類的初始化函數中的filter實參)。使用QuerySet.filter()排除行會更高效。集合的filter參數只當對同一關系使用兩個或更多不同條件的集合時才有用,下面Author反向關系引用Book(同一關系)的兩個Count集合(兩個),第二個需要對Count作出過濾(不同條件),。 Author.objects.annotate( ? ? num_books=Count('book'), ? ? highly_rated_books=Count( 'book', filter=Q(book__rating__gte=7) ) ? ? |
總結
以上是生活随笔為你收集整理的Django ORM查询之外键、关系的反向引用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 天猫模拟登陆_爬虫登录 最好是
- 下一篇: M1 Mac使用Kitty script