[英]Django: For a fixed len. model list relation, is it OK to use a fixed number of OneToOneField's in a parent model rather than a FK in the child model?
[英]Django annotation on (model → FK → model) relation
宇宙中的星系擁有數百萬/數十億顆恆星,每顆恆星都屬於特定類型,具體取決於其物理特性(紅星、藍超巨星、白矮星等)。 對於我的數據庫中的每顆恆星,我試圖找到同樣類型的恆星所在的不同星系的數量。
class Galaxy(Model):
...
class Star(Model):
galaxy = ForeignKey(Galaxy, related_name='stars')
type = CharField(...)
可以通過以下方式輕松地為每個 Star 單獨執行此查詢:
star = <some_Star>
desired_galaxies = Galaxy.objects.filter(stars__type=star.type).distinct()
desired_count = desired_galaxies.count()
甚至,雖然更加多余:
desired_count = Star.objects.filter(galaxy__stars__type=star.type).values('galaxy').distinct()
當我嘗試在“單個”查詢中獲取所有星星的計數結果時,這會變得有點模糊:
all_stars = Star.objects.annotate(desired_count=...)
我想這樣做的主要原因是能夠以干凈的方式對Star.objects.order_by('desired_count')
進行排序。
到目前為止我嘗試過的:
Star.annotate(desired_count=Count('galaxy', filter=Q(galaxy__stars__type=F('type')), distinct=True))
但這為每顆星注釋了1
。 我想我將不得不在這里使用OuterRef, Subquery
,但不確定如何使用。
您可以使用GROUP BY
來獲取計數:
Star.objects.values('type').annotate(desired_count=Count('galaxy')).values('type', 'desired_count')
Django 沒有提供一種方法來定義不涉及外鍵的模型之間的多值關系。 如果是這樣,你可以做類似的事情
class Galaxy(Model):
...
class Star(Model):
galaxy = ForeignKey(Galaxy, related_name='stars')
type = CharField(...)
same_type_stars = Relation(
'self', from_fields=('type',), to_fields=('type',)
)
Star.objects.annotate(
galaxies_count=Count('same_type_stars__galaxy', distinct=True)
)
這會導致一些事情
SELECT
star.*,
COUNT(DISTINCT same_star_type.galaxy_id) galaxies_count
FROM star
LEFT JOIN star same_star_type ON (same_star_type.type = star.type)
GROUP BY star.id
如果你想實現類似的東西,你現在需要使用子查詢
Star.objects.annotate(
galaxies_count=Subquery(Star.objects.filter(
type=OuterRef('type'),
).values('type').values(
inner_count=Count('galaxy', distinct=True),
))
)
這會導致一些事情
SELECT
star.*,
(
SELECT COUNT(DISTINCT inner_star.galaxy_id)
FROM star inner_star
WHERE inner_star.type = star.type
GROUP BY inner_star.type
) galaxies_count
FROM star
這可能在一些沒有實現相關子查詢的數據庫(例如 MySQL)上表現不佳。 在所有情況下,請確保對Star.type
進行索引,否則Star.type
都會獲得糟糕的性能。 ('type', 'galaxy')
上的復合索引可能會更好,因為它可能允許您執行僅索引掃描(例如在 PostgreSQL 上)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.