2016-07-14 10 views
0

カテゴリとアイテムがあります。項目には終了フィールド(datetime)があります。今、私はすべてのカテゴリを一覧表示し、関連するアイテム数とアイテムのアイテム数を将来表示する必要があります。例として:datetimeでフィルタリングされた数をアノテーションする方法は?

  • Cat Foo、2個の商品は、将来的には1個となります。
  • 今後Cat n、n個のアイテムがあります。

リストは大きくなります。だから、データベースは重労働をして、item_countfuture_item_countの両方に注釈を付けなければなりません。

モデル:

from django.db import models 

class Cat(models.Model): 
    title = models.CharField(max_length=200) 

class Item(models.Model): 
    cat = models.ForeignKey(Cat) 
    title = models.CharField(max_length=200) 
    end = models.DateTimeField() 

は、カテゴリと二つの関連項目を作成します。過去1、将来的には1:

from datetime import timedelta 
from django.utils import timezone 

cat = Cat(title='Cat 1') 
cat.save() 

item_1 = Item(cat=cat, title="Item 1", end=timezone.now() - timedelta(days=1)) 
item_1.save() 

item_2 = Item(cat=cat, title="Item 2", end=timezone.now() + timedelta(days=1)) 
item_2.save() 

私はITEM_COUNTに注釈を付けるときに期待どおりに動作します:

from django.db.models import Count 

Cat.objects.all().annotate(
    item_count=Count('item')).values('title', 'item_count') 
# [{'item_count': 2, 'title': u'Cat 1'}] 

私はItem.end(日時)によってフィルタリングにコメントを付けることはできません。これはDjangoのクエリで可能ですか?

Cat.objects.all().annotate(
    item_count=Count('item'), 
    future_item_count=Count('item').filter(
     end__gt=timezone.now()) 
    ).values(
     'title', 
     'item_count', 
     'future_item_count' 
    ) 
# AttributeError: 'Count' object has no attribute 'filter' 

私が得ることを期待:[{'item_count': 2, 'future_item_count': 1, 'title': u'Cat 1'}]

を私はまたRawSQLを試みたが、SQLのスキルが不足している:

from django.db.models.expressions import RawSQL 

Cat.objects.all().annotate(
    item_count=Count('item'), 
    future_item_count=RawSQL(
     """SELECT COUNT(*) 
      FROM project_item 
      JOIN project_item 
      AS foo 
      ON foo.cat_id = project_cat.id 
      WHERE project_item.end < NOW()""", 
     "" 
    )).values(
     'title', 
     'item_count', 
     'future_item_count' 
    ) 
# [{'item_count': 2, 'future_item_count': 2L, 'title': u'Cat 1'}] 

しかし、私はWHERE project_item.end > NOW()"WHERE project_item.end < NOW()"を変更するとき、私は同じ結果を得る:

[{'item_count': 2, 'future_item_count': 2L, 'title': u'Cat 1'}] 

生のSQLをフォーマットする方法は?または、これはDjangoのクエリで行うことができますか?

+0

「カウント」でフィルタリングすることはできません。あなたは 'Case'式を探しています。[documentation](https://docs.djangoproject.com/en/1.9/ref/models/conditional-expressions/#case)を見てください – dnaranjo

+0

@dnaranjoありがとう提案。私はドキュメントのこの部分を読んだが、アノテーションに 'then'の値を使用するため、オプションを破棄しました。たぶん私は何かが欠けているでしょう。生の答えを受け入れたにもかかわらず、私はまだ生のSQLに落ちることなくこれを行う方法を知りたいです。 – allcaps

答えて

1

私は個人的には(まだ.extraで物事を行う)RawSQLを使用していないが、私はあなたのRawSQL文でJOIN project_itemする必要はありませんだと思います。

RawSQL("""SELECT COUNT(*) 
      FROM project_item 
      WHERE 
       project_item.cat_id = project_cat.id 
       AND project_item.end < NOW() 
""") 

そしてもう一つは、私はあなたが.annotate AFTER .valuesを使用してはならないと思いますが、、BEFORE注釈:だけでみてください。したがって、完全なクエリセットは次のようになります。

Cat.objects.values('title')\ 
    .annotate(
     item_count=Count('item'), 
     future_item_count=RawSQL(""" 
      SELECT COUNT(*) 
      FROM project_item 
      WHERE 
       project_item.cat_id = project_cat.id 
       AND project_item.end < NOW() 
      """) 
    ) 
+0

ありがとうございます。私はそれをスピンします。サンプルコードの値だけを追加しました。より良い結果をプリントします。アプリケーションでは、私は完全なオブジェクトを使用します。 – allcaps

+0

私は動作します!すばらしいです。 RawSQLには2つの値が必要です。 1つはクエリで、2つ目はパラメータです。私は空の文字列を与えた。 – allcaps

関連する問題