【问题标题】:Django annotation has side effect on another annotationDjango注解对另一个注解有副作用
【发布时间】:2019-10-26 07:46:12
【问题描述】:

我遇到了一个问题,向 QuerySet 添加注释会更改以前注释的结果。

这是(简化的)设置:

class Player(models.Model):
    name = models.CharField()

class Unit(models.Model):
    player = models.ForeignKey(Player, on_delete=models.CASCADE,
                               related_name='unit_set')

    rarity = models.IntegerField()

class Gear(models.Model):
    pass

class UnitGear(models.Model):
    unit = models.ForeignKey(Unit, on_delete=models.CASCADE,
                             related_name='ug_set')
    gear = models.ForeignKey(Gear, on_delete=models.PROTECT)

用稀有 7 个单位来注释玩家效果很好:

Player.objects.annotate(
    rarity7_count=Count(unit_set__rarity=7)
).values_list('name', 'rarity7_count')

[('Player1', 170),
 ('Player2', 172),
 ('Player3', 164),
 ...,
)]

上面为rarity7_count 返回的值是正确的。

如果我添加以下附加注释,则不再是这种情况:

Player.objects.annotate(
    rarity7_count=Count(unit_set__rarity=7),
    gear_count=Count(unit_set__ug_set)
).values_list('name', 'rarity7_count', 'gear_count')

[('Player1', 476, 456),
 ('Player2', 490, 466),
 ('Player3', 422, 433),
 ...,
)]

注意rarity7_count 值的变化——这些值不再正确!但是,gear_count 的值是正确的。

这是为什么呢?如何在不相互干扰的情况下让两个注释都工作?我已经尝试了各种方法,但目前不知道如何做到这一点。

【问题讨论】:

  • 是的,既然你做了两个JOINs,这将充当某种“乘数”。
  • @WillemVanOnsem:我可以找到一些关于此的文档(在 Django 级别)吗?如何使用单个 QuerySet 实现我打算在这里做的事情?

标签: python django django-annotate


【解决方案1】:

是的,因为现在有两个JOINs,并且由于Count(..) [Django-doc]是行数,因此它将充当某种乘数。

我们可以通过指定distinct=True 来解决这个问题,例如:

Player.objects.annotate(
    rarity7_count=Count('unit_set', distinct=True, filter=Q(unit_set__rarity=7)),
    gear_count=Count('unit_set__ug_set')
).values_list('name', 'rarity7_count', 'gear_count')

请注意,如果您希望 gear_count 也过滤稀有度,则需要再次指定 filter= 部分。

【讨论】:

  • 非常感谢 - 这行得通。我有一个后续问题:我现在正在尝试在此注释中添加Sumr7_sum=Sum('unit_set__rarity', filter=Q(unit_set__rarity=7))(现实不那么琐碎,但我正在适应上面的模型)。使用Sum,我得到的结果太大(与我假设的问题相同),而使用answerDistinctSum,结果太低。我错过了什么?我应该写一个新问题吗?
  • @abey:filtering 可能与此处相关,因为对于过滤器,您经常添加一些不可为空的额外约束,因此我建议您制定 MWE可以重现错误。
  • 完成,这里是the question
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 2019-05-27
  • 1970-01-01
  • 1970-01-01
  • 2020-06-03
相关资源
最近更新 更多