【发布时间】:2017-09-04 21:39:00
【问题描述】:
我正在学习 Django,但遇到了一个小问题:
我有一个具有相关行的模型,我想得到相关行的列的总和,按第二列的值分组。
我正在使用的模型如下:
class Integrante(models.Model):
nombre = models.CharField(max_length=80, db_index=True)
class EstadoCuenta(models.Model):
num_edc = models.PositiveIntegerField(validators=[MinValueValidator(1),])
fecha_edc = models.DateField(null=True, db_index=True)
class Movimiento(models.Model):
TIPOS_MOVIMIENTO = (
# Choices for column 'tipo'
)
estado_cuenta = models.ForeignKey(EstadoCuenta, on_delete=models.CASCADE)
integrante = models.ForeignKey(Integrante, on_delete=models.CASCADE)
fecha = models.DateField(db_index=True)
tipo = models.SmallIntegerField(db_index=True, choices=TIPOS_MOVIMIENTO)
descripcion = models.CharField(max_length=200, blank=True)
importe = models.DecimalField(max_digits=8, decimal_places=2)
class Meta:
ordering = ['integrante', 'fecha', 'tipo', 'pk']
我尝试了以下方法:
edc = EstadoCuenta.objects.filter(grupo__nombre_grupo='A group').latest()
edc.movimiento_set.values('integrante').annotate(Sum('importe'))
但是,我得到以下结果:
for x in edc.movimiento_set.values('integrante').annotate(Sum('importe')):
print(x)
# {'integrante': 28, 'importe__sum': Decimal('-20.00')}
# {'integrante': 28, 'importe__sum': Decimal('23.00')}
# {'integrante': 28, 'importe__sum': Decimal('9.60')}
# {'integrante': 28, 'importe__sum': Decimal('20.00')}
# {'integrante': 28, 'importe__sum': Decimal('-0.60')}
# {'integrante': 24, 'importe__sum': Decimal('96.00')}
# {'integrante': 24, 'importe__sum': Decimal('28.80')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('28.80')}
# {'integrante': 24, 'importe__sum': Decimal('96.00')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('288.00')}
# {'integrante': 24, 'importe__sum': Decimal('144.00')}
# {'integrante': 24, 'importe__sum': Decimal('19.20')}
# {'integrante': 24, 'importe__sum': Decimal('-510.00')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('48.00')}
# {'integrante': 24, 'importe__sum': Decimal('35.00')}
# {'integrante': 24, 'importe__sum': Decimal('235.00')}
# {'integrante': 24, 'importe__sum': Decimal('-0.80')}
# ...
我想要得到的结果是这样的(直接在数据库服务器中完成):
select integrante_id, sum(importe)
from core_movimiento
where estado_cuenta_id=233
group by integrante_id;
-- | integrante_id | sum(importe) |
-- +---------------+--------------+
-- | 24 | 844.00 |
-- | 25 | 0.00 |
-- | 26 | 0.00 |
-- | 27 | -232.00 |
-- | 28 | 32.00 |
-- | 29 | 0.00 |
-- | 30 | 20.00 |
你能指出正确的方向吗?
我正在使用 Python 3.6 和 Django 1.11
奖金
我还想得到importe 的总和,这取决于列tipo 的值。在 SQL 中,我可以这样得到:
select integrante_id
, sum(case when tipo=1 then importe else 0 end) as pagos
, sum(case when tipo in (11, 12) then importe else 0 end) as ventas
, sum(case when tipo in (70, 71) then importe else 0 end) as paquetes
, sum(case when tipo=99 then importe else 0 end) as ajustes
, sum(importe) as total
from core_movimiento
where estado_cuenta_id = 233
group by integrante_id;
-- | integrante_id | pagos | ventas | paquetes | ajustes | total |
-- +---------------+---------+---------+----------+---------+---------+
-- | 24 | -510.00 | 1084.80 | 270.00 | -0.80 | 844.00 |
-- | 25 | -35.00 | 0.00 | 35.00 | 0.00 | 0.00 |
-- | 26 | -20.00 | 0.00 | 20.00 | 0.00 | 0.00 |
-- | 27 | -422.00 | 190.00 | 0.00 | 0.00 | -232.00 |
-- | 28 | -20.00 | 32.60 | 20.00 | -0.60 | 32.00 |
-- | 29 | -200.00 | 0.00 | 200.00 | 0.00 | 0.00 |
-- | 30 | 0.00 | 0.00 | 20.00 | 0.00 | 20.00 |
有什么想法吗?
【问题讨论】:
-
你的模型中有
orderingmeta吗? -
这是一个很好的问题。特别是奖金部分!一个好的答案可以做到这一点,而无需使用 django ORM 对数据库进行多次往返。你认为劫持 django ORM 是一个合理的答案吗?就像通过 django 进行原始 sql 查询:docs.djangoproject.com/en/1.11/topics/db/sql
-
@BearBrown 刚刚将
Meta类添加到Movimiento。我应该在订单中只留下'integrante吗? -
@Tico 我会检查的。我想使用 ORM(仅用于学习目的),但如果最简单的方法是发送原始查询,我会使用它
标签: django django-models group-by aggregate