我有一个看起来像这样的模型:
class Category(models.Model):
name = models.CharField(max_length=60)
class Item(models.Model):
name = models.CharField(max_length=60)
category = models.ForeignKey(Category)
Run Code Online (Sandbox Code Playgroud)
我想要为每个类别选择项目的计数(只是计数),所以在SQL中它就像这样简单:
select category_id, count(id) from item group by category_id
Run Code Online (Sandbox Code Playgroud)
有没有相当于这样的"Django方式"?或者纯SQL是唯一的选择吗?我熟悉Django中的count()方法,但我不知道group by是如何适合的.
在构建QuerySet带有多个批注的复合体时,我遇到了一个问题,该问题可以通过以下简单设置重现。
这些是模型:
class Player(models.Model):
name = models.CharField(max_length=200)
class Unit(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE,
related_name='unit_set')
rarity = models.IntegerField()
class Weapon(models.Model):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE,
related_name='weapon_set')
Run Code Online (Sandbox Code Playgroud)
使用我的测试数据库,可以获得以下(正确)结果:
Player.objects.annotate(weapon_count=Count('unit_set__weapon_set'))
[{'id': 1, 'name': 'James', 'weapon_count': 23},
{'id': 2, 'name': 'Max', 'weapon_count': 41},
{'id': 3, 'name': 'Bob', 'weapon_count': 26}]
Player.objects.annotate(rarity_sum=Sum('unit_set__rarity'))
[{'id': 1, 'name': 'James', 'rarity_sum': 42},
{'id': 2, 'name': 'Max', 'rarity_sum': 89},
{'id': 3, 'name': 'Bob', 'rarity_sum': 67}]
Run Code Online (Sandbox Code Playgroud)
如果现在将两个批注合并到相同的QuerySet,我将获得不同的(不准确的)结果:
Player.objects.annotate(
weapon_count=Count('unit_set__weapon_set', distinct=True),
rarity_sum=Sum('unit_set__rarity'))
[{'id': 1, 'name': 'James', 'weapon_count': 23, 'rarity_sum': 99}, …Run Code Online (Sandbox Code Playgroud) 我遇到了一个问题,即向查询集添加注释会更改以前注释的结果。
这是(简化的)设置:
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)
Run Code Online (Sandbox Code Playgroud)
用稀有度 7 单位的数量来注释玩家效果很好:
Player.objects.annotate(
rarity7_count=Count(unit_set__rarity=7)
).values_list('name', 'rarity7_count')
[('Player1', 170),
('Player2', 172),
('Player3', 164),
...,
)]
Run Code Online (Sandbox Code Playgroud)
上面返回的值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),
...,
)]
Run Code Online (Sandbox Code Playgroud)
请注意值是如何rarity7_count变化的——这些值不再正确!gear_count然而,的值是正确的。
这是为什么?如何让两个注释同时工作而不互相干扰?我已经尝试过各种各样的事情,但目前不知道如何做到这一点。