110

次のような単純なモデルがあります。

class Order(models.Model):
    created = model.DateTimeField(auto_now_add=True)
    total = models.IntegerField() # monetary value

そして、次の月ごとの内訳を出力したいと思います。

  • 1 か月の販売数 ( COUNT)
  • 合計値 ( SUM)

これを攻撃する最善の方法が何であるかはわかりません。かなり恐ろしく見える余分な選択クエリを見たことがありますが、私の単純な心は、任意の開始年/月から開始して現在の月に到達するまでカウントアップして、単純なその月のクエリ フィルタリング。より多くのデータベース作業 - 開発者のストレスを軽減!

あなたにとって最も意味のあることは何ですか? データの簡単なテーブルを元に戻す良い方法はありますか? それとも、私の汚い方法がおそらく最良のアイデアですか?

私はDjango 1.3を使用しています。GROUP_BY彼らが最近より良い方法を追加したかどうかはわかりません。

4

8 に答える 8

259

Django 1.10 以降

Django のドキュメントには、まもなく非推奨となるリストextra記載されています。(@ seddonym、@ Lucas03を指摘してくれてありがとう)。チケットを開きましたが、これが jarshwah が提供したソリューションです。

from django.db.models.functions import TruncMonth
from django.db.models import Count

Sales.objects
    .annotate(month=TruncMonth('created'))  # Truncate to month and add to select list
    .values('month')                          # Group By month
    .annotate(c=Count('id'))                  # Select the count of the grouping
    .values('month', 'c')                     # (might be redundant, haven't tested) select month and count 

古いバージョン

from django.db import connection
from django.db.models import Sum, Count

truncate_date = connection.ops.date_trunc_sql('month', 'created')
qs = Order.objects.extra({'month':truncate_date})
report = qs.values('month').annotate(Sum('total'), Count('pk')).order_by('month')

編集

  • 追加された数
  • django >= 1.10 の追加情報
于 2012-01-05T17:03:43.240 に答える
13

別のアプローチは、 を使用することExtractMonthです。日時の年の値が 1 つしか返されないため、TruncMonth を使用して問題が発生しました。たとえば、2009 年の月だけが返されていました。ExtractMonth はこの問題を完全に修正し、以下のように使用できます。

from django.db.models.functions import ExtractMonth
Sales.objects
    .annotate(month=ExtractMonth('timestamp')) 
    .values('month')                          
    .annotate(count=Count('id'))                  
    .values('month', 'count')  
于 2016-12-01T21:54:48.620 に答える
4
    metrics = {
        'sales_sum': Sum('total'),
    }
    queryset = Order.objects.values('created__month')
                               .annotate(**metrics)
                               .order_by('created__month')

これquerysetは、売上の合計を組み合わせた、月ごとに 1 行の Order のリストです。sales_sum

@ジャンゴ2.1.7

于 2019-07-31T03:16:23.620 に答える
1

これが私の汚い方法です。これは汚れた。

import datetime, decimal
from django.db.models import Count, Sum
from account.models import Order
d = []

# arbitrary starting dates
year = 2011
month = 12

cyear = datetime.date.today().year
cmonth = datetime.date.today().month

while year <= cyear:
    while (year < cyear and month <= 12) or (year == cyear and month <= cmonth):
        sales = Order.objects.filter(created__year=year, created__month=month).aggregate(Count('total'), Sum('total'))
        d.append({
            'year': year,
            'month': month,
            'sales': sales['total__count'] or 0,
            'value': decimal.Decimal(sales['total__sum'] or 0),
        })
        month += 1
    month = 1
    year += 1

年/月をループするより良い方法があるかもしれませんが、それは私が本当に気にかけていることではありません:)

于 2012-01-05T16:59:35.270 に答える
0

月ごと:

 Order.objects.filter().extra({'month':"Extract(month from created)"}).values_list('month').annotate(Count('id'))

年別:

 Order.objects.filter().extra({'year':"Extract(year from created)"}).values_list('year').annotate(Count('id'))

日ごとに:

 Order.objects.filter().extra({'day':"Extract(day from created)"}).values_list('day').annotate(Count('id'))

Count をインポートすることを忘れないでください

from django.db.models import Count

ジャンゴ < 1.10 の場合

于 2016-12-28T07:20:27.830 に答える