Skip to main content
 首页 » 编程设计

python之Django 注解对另一个注解有副作用

2024年09月03日35开发

我遇到了一个问题,即向 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 的值是正确的。

这是为什么呢?如何让两个注释在不相互干扰的情况下工作?我已经尝试了各种各样的事情,但目前对如何做到这一点一头雾水。

请您参考如下方法:

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

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

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

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