Django Query API select_lated 在多表计数查询中

问题描述 投票:0回答:1

想象一下,我正在尝试计算某个公园中树木品种的数量,并且这些树木被分组在公园内的特定区域中。 一个问题是树木可以重新种植,所以我只想计算现有的树木和空位置(

removed IS NULL
表示当前种植的树木,
LEFT
RIGHT JOIN
表示尚未种植的位置)。 在浏览了大量 Django
select_related
帖子和文档后,我不知道如何通过 Django 的查询 API 来做到这一点。 我有公园 ID,所以我将从
views.py
中的 Parks 模型开始执行此操作。

我在 Django 的查询 API 中遗漏了一些明显(或不明显)的东西吗?

以下 SQL 执行我想要的操作:

WITH p AS (
    SELECT t.cultivar, l.id AS loc
    FROM trees t
    JOIN locations l ON t.location = l.id
    JOIN fields d ON l.field = d.id 
    WHERE d.park = 'SOME_PARK_ID'
        AND t.removed IS NULL
    )
SELECT c.name, count(*)
FROM p
LEFT JOIN cultivars c ON p.cultivar = c.id
RIGHT JOIN locations l ON p.loc = l.id
GROUP BY name;

例如:

+--------+-------+
| name   | count |
|--------+-------|
| <null> | 2     |
| HGG    | 2     |
| BOX    | 3     |
| GRV    | 1     |
+--------+-------+

可能

views.py
:

class ParkDetail( DetailView ):
    model = Parks
    # Would like to get a count of cultivars here
    def get_context_data( self, **kwargs ):  # ... Lost here
        qry = Parks.objects.select_related( 'tree__location__field' ).filter( tree.removed is None )
        tree_count = qry.annotate( Count( ... ) )

models.py
的德语部分:

class Parks( models.Model ):
    name = models.CharField( max_length = 64, blank = False )

class Fields( models.Model ):
    park = models.ForeignKey( Parks, on_delete = models.CASCADE )

class Locations( models.Model ):
    field = models.ForeignKey( Fields, on_delete = models.CASCADE )

class Cultivars( models.Model ):
    name = models.CharField( max_length = 64, blank = False )

class Trees( models.Model ):
    location = models.ForeignKey( Locations, on_delete = models.CASCADE )
    cultivar = models.ForeignKey( Cultivars, on_delete = models.PROTECT )
    planted = models.DateField( blank = False )
    removed = models.DateField( blank = True, null = True )

sql django common-table-expression django-orm
1个回答
0
投票

我不明白你在这里需要什么

.select_related(…)
。您可以使用以下方法计算给定
Trees
未删除的
park_id

from django.db.models import Count

Cultivars.objects.filter(
    tree__removed=None, tree_location__field__park_id=my_park_id
).annotate(tree_count=Count('tree'))

由这个

Cultivars
产生的
QuerySet
将有一个名为
.tree_count
的额外属性,其中未删除的
Trees
的数量为
my_park_id
park_id

如果您还想检索未种植树木的

Cultivars
,我们可以使用:

from django.db.models import Case, Count, F, Value, When

Cultivars.objects.annotate(
    tree_count=Count(
        Case(
            When(
                tree__removed=None,
                tree_location__field__park_id=my_park_id,
                then=F('tree'),
            ),
            default=Value(None),
        )
    )
)
© www.soinside.com 2019 - 2024. All rights reserved.