python - 如何计算 Django 中跨字段的值?

标签 python django django-queryset

模型

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

class ModelB(models.Model):
    MY_CHOICES = (
        ('X', 'X'),
        ('Y', 'Y'),
        ('Z', 'Z'),
    )
    modela = models.ForeignKey(ModelA, on_delete=models.CASCADE)
    txt_1 = models.CharField(choices=MY_CHOICES)
    txt_2 = models.CharField(choices=MY_CHOICES)

鉴于上面的简化示例,如果有两个字段需要计算,我如何计算每个选项值被记录了多少次?

理想情况下,结果应该是这样的:

{'X': 15, 'Y': 27, 'Z': 89}

我尝试了以下方法,但在我的真实模型中,我有大约 20 个字段要计算,这并没有给出我希望的结果:

ModelA.objects.values('modelb__txt1', 'modelb__txt2').annotate(Count('modelb__txt1', 'modelb__txt2'))

我之前创建了巨大的字典并手动对值进行排序/计数,但现在这是难以管理且丑陋的。

最佳答案

使用一个查询(对于有限数量的列)

通过一个查询,我们可以这样做:

from django.db.models import Count

qs = ModelB.objects.values('txt_1', 'txt_2').annotate(
    cnt=Count('id')
).order_by('txt_1', 'txt_2')

但现在我们仍然没有,因为现在我们有 txt_1txt_2 的每个组合的元素数量。我们想将其“扁平化”到每个单独的选择。例如,我们可以通过构造一个 Counter [Python-doc] 来做到这一点。 :

from collections import Counter

result = Counter()
for row in qs:
    result[row['txt_1']] += row['cnt']
    result[row['txt_2']] += row['cnt']

对于此 QuerySet 的每一行,我们因此将数字 (cnt) 添加到两个键。因此,这意味着我们对 txt_1txt_2 都具有值 'X' 两次的行进行计数。

Counter 是字典的子类,但如果您想将其转换为 dictionary,您可以稍后编写:

result_dict = dict(result)

从未选择的选项将不会出现在字典中,因为查询集不会包含这些,因此我们永远不会将这些添加到 Counter。但是我们当然可以对字典进行后处理,并为这些添加0。

n 个查询(n 个列数)

以上通常会很好地工作。但是,如果选择的数量很大,则处理将更多地在 Python 端进行,这通常较慢。然后我们可以进行线性化,并处理两个查询:

from collections import Counter
from django.db.models import Count

result = Counter()
for col in ['txt_1', 'txt_2']:
    qs = ModelB.objects.values(col).annotate(cnt=Count('id')).order_by(col)
    result.update({q[col]: q['cnt'] for q in qs})

这将减少两个查询。但在这种情况下,每个查询将(最多)返回三行。而另一种方法将导致一个查询返回(最多)九行。对于少量行,这不是问题。但是案例的数量很容易随列数呈指数增长。

关于python - 如何计算 Django 中跨字段的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51557568/

相关文章:

python正则表达式返回非捕获组

开始大于停止的 Python 范围

python - 使用 django 序列化程序将数据保存在数据库中的更好方法

django - 如何判断 Django session 是否是新 session ?

python - Django 在单个查询集中组合外键

Django 按日期排序,但末尾有 "None"?

python - 在apsw上复现pysqlite的row_factory

python - 使用隐马尔可夫模型对数据流进行分类

django - Jasig CAS 身份验证重定向循环

django - 'RelatedManager' 对象不是可迭代的 Django