2017-10-01 24 views
0

私は2つのモデルを持っているとしましょう。Django Rest DRF:逆の関係のオブジェクトの数を取得する

モデル今

class Item(models.Model): 
    name = models.CharField(max_length=32) 
    # other fields 

class ItemRelation(models.Model): 
    item = models.ForeignKey(Item, related_name='relations_item') 
    user = models.ForeignKey(User, related_name='relations_user') 
    has_viewed = models.BooleanField(default=False) 
    has_loved = models.BooleanFields(default=False) 

、私がやりたいことは、私はジャンゴのREST APIを使用して、すべてのアイテムのVIEW_COUNTとlove_countを取得したいです。

views.py

class ItemView(ListAPIView): 
    queryset = Items.objects.all().prefetch_related(Prefetch('relations_item', 
      queryset=ItemRelation.objects.filter(Q(has_viewed=True) | Q(has_loved=True)) 
      ) 
    serializer_class = ItemSerializer 

まあ、これは計画だったが、私は、リスト-API-ビューの各項目についてVIEW_COUNTとlove_countを取得する方法を絶対にないアイデアを持っていません。私はシリアライザでかなりのことを試しましたが、うまくいくとは思えません。 しかし、私はSerializerMethod()を使用して作業を行うことができますが、それはDB N + 1回数回ります。私はprefetch_relatedのためのいくつかの他のブログと一緒にドキュメントを読んで、私はこのカウントの問題が現れるまで簡単にやることができました。

シリアライザのサンプル。

class ItemSerializer(serializers.ModelSerializer): 

    class Meta: 
     model = Item 
     fields = ['name', 'relations_item'] 
+1

'prefetch_related'が、ここで適切なツールではありません。あなたは実際の関連オブジェクトを気にしない、あなたはちょうどカウントが欲しい。 ['annotate'](https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset)が必要です。 –

+0

私は、少なくともdbヒットでそれをしたいです。私がカウントを使用する場合、私のAPIは各項目に対してdbを2回ヒットします。私はまだ注釈を正しく使用する方法を理解できませんでした.Expを誰かが見たり愛しているかどうかによって、真の値またはヌル値しか得られませんでした。私は何か間違っていると確信しています... – flaire

答えて

1

私はhas_loved==True)あなたがA)has_viewed==True関係aとbの数をカウントするとします。 Django Conditional Expressionsannotate()を使用することにより可能である必要があり

from django.db.models import Case, IntegerField, Sum, When 


class ItemView(ListAPIView): 
    queryset = Items.objects.annotate(
        view_count=Sum(
         When(relations_item__has_viewed=True, then=1), 
         output_field=IntegerField(), 
        ), 
        love_count=Sum(
         When(relations_item__has_loved=True, then=1), 
         output_field=IntegerField(), 
        ), 
       ) 
    # ... 
+1

ああ...私はビューで注釈を使用するはずだったので、私はシリアライザファイルで同じことをしようとしていました:Dありがとう – flaire

関連する問題