【问题标题】:Self-referential aggregation in djangoDjango中的自引用聚合
【发布时间】:2018-12-03 00:04:22
【问题描述】:

是否可以在 django 中编写自引用聚合?

例如,给定以下模型定义:

from django.db import models

class Match(models.Model):
    match_id = models.BigIntegerField(primary_key=True)
    start_time = models.DateTimeField()
    league = models.ForeignKey(League, on_delete=models.CASCADE)
    team = models.ForeignKey(Team, on_delete.models.CASCADE)

我想用先前匹配的数量来注释每个 Match 对象。 (最终还有其他条件,例如,与给定球队的先前比赛。)

我最初的想法是这样的:

from django.db.models import Q, F, Count

matches = Match.objects.filter(team__name='xyz')

matches.annotate(
    prior_matches=Count('match_id', filter=(
        Q(start_time__lt=F('start_time')
    ))
)

不幸的是,这似乎为所有对象提供了prior_matches=0

This question建议遵循外键并使用反向关系,但这看起来很笨拙,而且还有两个问题:

  1. 这不是严格等价的。例如,以下 sn-p 有效,但将计算给定联赛中的先前比赛,而不是整体。我想你可以通过创建一个占位符模型来解决这个问题,所有 Match 对象都将其作为外键,但这似乎并不理想。

matches.annotate(
     prior_matches=Sum(Case(
         When(start_time__lt=F('league__matches__start_time'), then=1),
         default=0,
         output_field=models.IntegerField()
     ))
)
  1. 提供的计数与数据库中所有先前的匹配相关,而不仅仅是过滤查询集中的匹配。例如,即使 matches 查询集已针对特定团队过滤,上述代码也会查找所有先前匹配项的计数。我想不出解决这个问题的好方法(除了在每个 Q / filter 子句中重复应用于查询集的完整过滤条件,这在经理中是不可推广的)。

为了避免 xy 问题,我希望通过在数据库级别工作来替换的(伪)代码的 sn-ps 之一如下:

def generate_stats(match):
    matches = Match.objects.filter(start_time__lt=match.start_time)

    for team in (match.home_team, match.away_team):
        q_involving = Q(home_team=team) | Q(away_team=team)
        team_matches = matches.filter(q_involving)

        team_matches.aggregate(...)  # get stats

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    我认为您应该将您的第一个代码更改为

    from django.db import models
    
    class Match(models.Model):
        match_id = models.AutoField(primary_key=True)
        start_time = models.DateTimeField()
        league = models.ForeignKey(League, on_delete=models.CASCADE)
        team = models.ForeignKey(Team, on_delete.models.CASCADE)
    

    否则,可能是您实际上没有添加“匹配”

    【讨论】:

    • 不幸的是,模型定义不是问题,数据存在。 (不需要将主键作为 AutoFields,尤其是在连接到外部数据源时。)
    猜你喜欢
    • 2013-10-04
    • 2015-01-08
    • 1970-01-01
    • 2010-12-20
    • 2012-01-15
    • 2014-07-15
    • 2011-02-02
    • 1970-01-01
    • 2017-09-23
    相关资源
    最近更新 更多