41

Django初心者の質問:)

私は次のモデルを持っています-各レビューは製品用であり、各製品には部門があります:

class Department(models.Model):
    code = models.CharField(max_length=16)
class Product(models.Model):
    id = models.CharField(max_length=40, primary_key=True, db_index=True)
    dept = models.ForeignKey(Department, null=True, blank=True, db_index=True)
class Review(models.Model):
    review_id = models.CharField(max_length=32, primary_key=True, db_index=True) 
    product = models.ForeignKey(Product, db_index=True) 
    time = models.DateTimeField(db_index=True) 

日付範囲(2012-01-01から2012-01-08)に対してDjangoクエリを実行し、部門IDで注釈が付けられたすべての部門のリストと、レビューされたその部門の製品の数を返したいのですが。その日付範囲中。

これは私の脳を少し揚げています:)

私は時間範囲のすべてのレビューを得ることができます:

 reviews = Review.filter(time__range=["2012-01-01", "2012-01-08"])

次に、各レビューには製品フィールドがあり、それらの各製品には部門コードがあると思います。しかし、カウントと部門IDを使用して、製品とコードでそれらをグループ化するにはどうすればよいですか?

あるいは、部門にリクエストしてから、どういうわけか、製品数で部門に注釈を付けるのが最善ですか?

4

5 に答える 5

43

できるだけ避けextraてください。集約ドキュメントには、ほぼ次rawの使用例があります。

ドキュメントから直接:

# Each publisher, each with a count of books as a "num_books" attribute.
>>> from django.db.models import Count
>>> pubs = Publisher.objects.annotate(num_books=Count('book'))
>>> pubs
[<Publisher BaloneyPress>, <Publisher SalamiPress>, ...]
>>> pubs[0].num_books
73

したがって、特定の例でこれを変更するには、次のようにします。

depts = Department.objects.
            filter(product__review__time__range=["2012-01-01", "2012-01-08"]).
            annotate(num_products=Count('product'))

別々の行の関数呼び出しは読みやすくするためのものであり、それに応じて移動する必要があります。私はこれをテストしていませんが、うまくいくはずです。

于 2012-07-11T02:54:10.310 に答える
5

過去数日間に同様のクエリをいくつか実行する必要がありましたが、クエリextraセット関数を使用してクエリセット内の各オブジェクトにフィルタリングされた製品数で注釈を付ける最も簡単な方法は次のとおりです。

start = ..  # need to be formatted correctly
end = ...
departments = Departments.objects.all().extra(select = {
     'product_count' : """ SELECT COUNT(*) FROM appname_department
                           JOIN appname_product
                               ON appname_product.dept_id = appname_department.id
                           JOIN appname_review 
                               ON appname_review.product_id = appname_product.id
                           WHERE appname_review.time BETWEEN %s AND %s
                       """
}, params=[start, end])

{% for department in departments %}
    {{ department.product_count }}
{% endfor %}
于 2012-07-11T01:26:39.713 に答える
0

集計のドキュメント https://docs.djangoproject.com/en/dev/topics/db/aggregation/#cheat-sheet

おそらく集約または注釈を使用する方法がありますが、私はこれを好みます:

departments = Department.objects.all()
for dept in departments : 
    # Get the number of reviewed products for a given range and department
    num_products = dept.product_set.filter(review__time__range=["2012-01-01", "2012-01-08"]).count()

モデルの機能として絶対に必要な場合:

class Department(models.Model) :
    ...
    def num_products(self, start_date, end_date) : 
        return self.product_set.filter(review__time__range=[start_date, end_date]).count()

編集

生のクエリを実行した場合(このようなもの)

sql = """SELECT COUNT(Product.*) as num_products, Department.*
    FROM Department
    LEFT OUTER JOIN Product ON Product.department = Department.id
    LEFT OUTER JOIN Review ON Product.id = Review.product
    WHERE Review.time BETWEEN "2012-01-01" AND "2012-01-08"
    GROUP BY Department.id"""

Department.objects.raw(sql)

num_products は、結果のすべての Dept インスタンスの属性になります。

フィールドとテーブル名を少しいじる必要があるかもしれません

于 2012-07-10T17:34:19.647 に答える
0

同様のデータモデルで同じ状況があります。

私の解決策は次のようなものでした:

 Department.objects \
.extra(where=["<review_table_name.time_field> BETWEEN <time1> AND <time2> "])\
.annotate(num_products=Count('product__review__product_id'))
于 2015-10-07T14:48:52.567 に答える