Eu tenho um modelo simples como este:
class Order(models.Model):
created = model.DateTimeField(auto_now_add=True)
total = models.IntegerField() # monetary value
E eu quero produzir um detalhamento mês a mês de:
- Quantas vendas houve em um mês (
COUNT
) - O valor combinado (
SUM
)
Não tenho certeza de qual é a melhor maneira de atacar isso. Já vi algumas consultas extra-selecionadas de aparência bastante assustadora, mas minha mente simples está me dizendo que seria melhor apenas iterar números, começando de um ano / mês inicial arbitrário e contando até chegar ao mês atual, descartando simples filtragem de consultas para aquele mês. Mais trabalho de banco de dados - menos estresse do desenvolvedor!
O que faz mais sentido para você? Existe uma maneira legal de obter uma tabela de dados rápida? Ou meu método sujo é provavelmente a melhor ideia?
Estou usando o Django 1.3. Não tenho certeza se eles adicionaram uma maneira mais agradável GROUP_BY
recentemente.
Respostas:
Django 1.10 e superior
A documentação do Django lista
extra
como obsoleta em breve . (Obrigado por apontar isso @seddonym, @ Lucas03). Abri um tíquete e esta é a solução fornecida pelo jarshwah.versões mais antigas
Editar% s
fonte
>>> qs.extra({'month':td}).values('month').annotate(Sum('total')) [{'total__sum': Decimal('1234.56'), 'month': datetime.datetime(2011, 12, 1, 0, 0)}]
'{}.timestamp'.format(model._meta.db_table)
USE_TZ
configuração do Django forTrue
, as duas versões não são exatamente equivalentes. A versão usandoTruncMonth
irá converter o carimbo de data / hora para o fuso horário especificado pelaTIME_ZONE
configuração antes de truncar, enquanto a versão usandodate_trunc_sql
irá truncar o carimbo de data / hora UTC bruto no banco de dados.Apenas uma pequena adição à resposta @tback: Não funcionou para mim com Django 1.10.6 e postgres. Eu adicionei order_by () no final para consertar.
fonte
TruncDate
permite que você agrupe por data (dia do mês)Outra abordagem é usar
ExtractMonth
. Tive problemas ao usar TruncMonth devido ao retorno de apenas um valor de ano datetime. Por exemplo, apenas os meses de 2009 foram devolvidos. ExtractMonth corrigiu esse problema perfeitamente e pode ser usado como a seguir:fonte
A
queryset
é uma lista de Ordem, uma linha por mês, combinando a soma das vendas:sales_sum
@Django 2.1.7
fonte
Aqui está meu método sujo. Está sujo.
Pode haver uma maneira melhor de repetir anos / meses, mas não é exatamente isso que me interessa :)
fonte
Aqui está como você pode agrupar dados por períodos arbitrários de tempo:
fonte
Por mês:
Por ano:
Por dia:
Não se esqueça de importar Count
Para django <1,10
fonte