代码之家  ›  专栏  ›  技术社区  ›  mevaka

Django计数并按两个字段的值分组

  •  1
  • mevaka  · 技术社区  · 6 年前

    我有一个这样的模型:

    CLASS_TYPE = ( ("A","A Class"), ("B", "B Class") , ("C", "C Class") , ("D", "D Class") ) 
    
    class Student(models.Model):
       systemId    = models.CharField(max_length=15, unique=True )
       studentNo   = models.CharField(max_length=15, unique=True )
       country     = models.CharField(max_length=50)
       clasType    = models.CharField(max_length=2, choices=CLASS_TYPE )
       recordDate = models.DateField() 
    ...
    

    有很多记录。

    我只对两个领域感兴趣” 国家 “和” 克拉斯佩 “。
    我要根据国家和总和计算所有的班级类型。

    我想买这个 list 的字典 Student 模型:

    [
        { "country":"USA" , "A" : Count_Of_A_Class_in_USA , "B" : Count_Of_B_Class_in_USA , "C" : countCinUSA , "D": count_D_in_USA , "Total" : total_students_in_USA } ,
        {"Country":"England" , "A" : A_in_England ...., "C":C_in_England... , "Total" : students_in_England }
    ]
    

    我怎么能拿到这个?

    1 回复  |  直到 6 年前
        1
  •  2
  •   willeM_ Van Onsem    6 年前

    我们可以首先查询每个国家和每个碎屑类型的 Student S:

    qs = Student.objects.values('country', 'clasType').annotate(
        n=Count('pk')
    ).order_by('country', 'clasType')

    现在我们可以使用 itertools.groupby [Python-doc] 要在更紧凑的词典中将这些词典组合在一起,请执行以下操作:

    from itertools import groupby
    from operator import itemgetter
    
    data = [
        {'country': c, ** { li['clasType']: li['n'] for li in l } }
        for c, l in groupby(qs, itemgetter('country'))
    ]

    但我们仍然需要“修补”:一个国家可能还没有全部 clasType S,我们可能想补充 0 对于这些,我们还需要计算总数。我们可以通过以下方式实现:

    for subd in data:
        total = 0
        for ct, _ in CLASS_TYPE:
            total += subd.setdefault(ct, 0)
        subd['Total'] = total

    现在 data 包含字典列表,每个字典 'country' 'Total' 密钥和每个 CLASS_TYPE 一把钥匙和 学生 为了那个 类类型 .