【问题标题】:Django strange behaviour of aggregation over custom ManyToMany fieldDjango 在自定义 ManyToMany 字段上的奇怪聚合行为
【发布时间】:2018-06-26 19:14:40
【问题描述】:

我在 django 的 ManyToMany 字段上遇到了一些意想不到的(对我而言)聚合行为。

我有以下架构:

class ContestTaskRelationship(models.Model):
    contest = models.ForeignKey('Contest', on_delete=models.CASCADE)
    task = models.ForeignKey('Task', on_delete=models.CASCADE)
    solved = models.ManyToManyField('User', related_name='contests_tasks_solved', blank=True)
    cost = models.IntegerField(default=0)

class Contest(models.Model):
    tasks = models.ManyToManyField('Task',
                                   related_name='contests',
                                   blank=True,
                                   through='ContestTaskRelationship')

class Task(models.Model):
    pass

然后我有一个任务和两个竞赛,与该任务相关。如果我尝试注释 ContestTaskRelationship 这样的模型数量(假设 contest 是比赛之一):

task = contest.tasks.annotate(number_solved=Count('contesttaskrelationship')).first()

我得到task.number_solved == 1,但是当我这样尝试时:

task = Task.objects.filter(id=1).annotate(number_solved=Count('contesttaskrelationship')).first()

我得到了预期的结果task.number_solved == 2。这是为什么?不是同一个对象同一个字段吗?

UPD:我发现在第一个示例中,在查询中添加了附加条件,contest_id 与相应比赛的id 进行了比较。它是否记录在某处?我找不到任何东西。

【问题讨论】:

    标签: django database django-aggregation


    【解决方案1】:

    当你写这段代码时:

    Task.objects.get(id=1)
    

    您将获得 Task 实例,并且您的 Task 模型中似乎有一个名为 'annotate' 且带有 'number_solved' 参数的方法。您不能在某些查询集方法之后进行任何注释:get、count、aggregation、last、first、exists 并且可能还有更多。此方法不返回查询集。

    如果您想查看查询,并进行比较。

    你可以做两件事:

    1. print(Contest.objects.all().query) # 将原始查询返回到数据库
    2. 安装 django-extensions 并使用此命令添加 shell:

      ~# python manage.py shell_plus --print-sql  
      

    如果你看到查询,你可以比较它并自己解决这个问题

    【讨论】:

      猜你喜欢
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-10
      • 1970-01-01
      相关资源
      最近更新 更多