【问题标题】:Average duplicates from specific columns in QuerySet in DjangoDjango QuerySet 中特定列的平均重复次数
【发布时间】:2020-03-13 14:22:25
【问题描述】:

我有一个我正在使用的 Django 模型,看起来像这样:

class FinancialAid(models.Model):
    RECEIVED_EVERY = (("J", "Jours"),
        ("S", "Semaines"),
        ("M", "Mois"))
    ID = models.AutoField(primary_key=True)
    Name = models.CharField(max_length=100, null=True, blank=True)
    Value = models.IntegerField(null=True, blank=True, default=-1)
    ReceivedEvery = models.CharField(max_length=15, null=True, blank=True, choices=RECEIVED_EVERY)
    Exchange = models.ForeignKey('Exchange', on_delete=models.CASCADE)

我能够访问我想要的信息,但我有一个问题,即我的 QuerySet 中的 NameReceivedEvery 列经常有重复项,但并不总是在 Value 上,而且从不在 @987654326 上@。

假设我扩展了以下 QuerySet:

financial_aid_qs = [
    (ID=1, Name="Aid1", Value=100, ReceivedEvery="M", Exchange=Exchange.objects.get(pk=1)),
    (ID=2, Name="Aid2", Value=200, ReceivedEvery="S", Exchange=Exchange.objects.get(pk=2)),
    (ID=3, Name="Aid1", Value=150, ReceivedEvery="M", Exchange=Exchange.objects.get(pk=3)),
    (ID=4, Name="Aid3", Value=100, ReceivedEvery="M", Exchange=Exchange.objects.get(pk=4))
]

如您所见,对于索引 1 和 3,我有相同的 NameReceivedEvery。我想做的是获取一个 QuerySet(或 ValuesQuerySet,尽管我似乎记得它已被删除),它将包含在Name 方面所有不同的 FinancialAid 对象,并平均出具有相同 Name 的 FinancialAid 对象的 Value。理想情况下,它会考虑到ReceivedEvery 可能不同这一事实,即使Name 相同(这都是平均值,因此不需要完美,这就是为什么为此,一个月是 30天或 4 周)。

有了这一切,结果应该是这样的:

financial_aid_qs = [
    (Name="Aid1", Value=125, ReceivedEvery="M"),
    (Name="Aid2", Value=200, ReceivedEvery="S"),
    (Name="Aid3", Value=100, ReceivedEvery="M")
]

如您所见,对于Aid1,该值已从 100 和 150 平均为 125,并且其他 Aid 尚未修改。

【问题讨论】:

  • 在 Django 中,您可以使用 values("Name") 按“名称”group your query,然后通过 annotate(avg_value=Avg("Value")) 进行注释以获取平均“值”。问题是你想要ReceivedEvery 的值是多少?仅当 both ReceivedEveryName 相同时才进行平均吗?或者你有其他规则来聚合ReceivedEvery
  • 仅当ReceivedEveryName 相同时取平均值,如果它们不同,则计算正确值以获得特定ReceivedEvery 的转换值,然后取平均值

标签: python django duplicates django-queryset average


【解决方案1】:

使用values() 聚合分组查询,例如:

financial_aid_qs = FinancialAid.objects.values("Name").annotate(avg_value=Avg("Value"))

这将返回一个查询集(当执行一个列表时)字典:

financial_aid_qs = [
    {'Name': "Aid1", 'avg_value': 125},
    {'Name': "Aid2", 'avg_value': 200},
    ...
]

如果您还想通过ReceivedEvery 进行区分,那么您只需按两个值分组:

financial_aid_qs = FinancialAid.objects.values('Name', 'ReceivedEvery').annotate(...)

>>> [{'Name': "Aid1", 'ReceivedEvery': "M", 'avg_value': 125}, 
     {'Name': "Aid1", 'ReceivedEvery': "S", 'avg_value': 200}, ...]

在这里,每周和每月的捐款将针对相同的“名称”分开。

使用conditional expression 根据其他值创建新值:

financial_aid_qs = FinancialAid.objects.annotate(
    factor=Case(
        When(ReceivedEvery="S", then=Value(4)),
        When(ReceivedEvery="M", then=Value(1)),
        output_field=IntegerField()
    )).annotate(
        total=F('factor')*F('Value')
    ).values('Name').annotate(
        avg_value=Avg('total')
    )

【讨论】:

  • 非常感谢!我如何区分ReceivedEvery 但如果ReceivedEveryS 而另一个Aid1ReceivedEveryM 则有一个Aid1 乘以4 的值
  • @MaxMichel 添加了该示例。
猜你喜欢
  • 2013-04-26
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 2017-03-15
相关资源
最近更新 更多