2017-10-01 7 views
0

Disons que j'ai deux modèles.Django Rest DRF: obtention du nombre d'objets pour la relation inverse

Modèle

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) 

Maintenant, ce que je veux faire est que je veux obtenir le view_count et love_count pour tous les éléments à l'aide django reste api.

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 

Eh bien, ce fut le plan, mais je n'ai absolument aucune idée de la façon d'obtenir le view_count et love_count pour chaque élément de la liste-api-vue. J'ai essayé pas mal de choses sur mon sérialiseur mais je ne pense pas que ça va marcher. Je peux cependant utiliser SerializerMethod() pour faire le travail, mais cela passerait par le DB N + 1 nombre de fois. J'ai lu les docs avec quelques autres blogs pour prefetch_related et j'ai été capable de faire les choses facilement jusqu'à ce que ce problème de compte apparaisse.

Juste un échantillon de mon sérialiseur.

class ItemSerializer(serializers.ModelSerializer): 

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

'prefetch_related' n'est pas l'outil ici; vous ne vous souciez pas de l'objet apparenté réel, vous voulez juste les comptes. Vous avez besoin de ['annoter '] (https://docs.djangoproject.com/fr/1.11/topics/db/aggregation/#generating-aggregates-for-each-item-in-a-queryset). –

+0

je veux le faire avec le moins de coups de db. si j'utilise le compte alors mon api frappe le DB deux fois pour chaque article. Je n'arrive toujours pas à comprendre comment utiliser correctement annoter, je reçois seulement une valeur vraie ou nulle selon que l'exp a été vue ou aimée par quelqu'un - tant qu'une personne l'a vu ou aimé je deviens vrai. Assez sûr que je fais quelque chose de mal ... – flaire

Répondre

1

Je suppose que vous voulez compter le nombre de relations dans lequel a) et b has_viewed==True) has_loved==True.

Cela devrait être possible en utilisant annotate() avec Django Conditional Expressions:

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

ahh ... donc je devais utiliser l'annotation dans les vues, j'essayais de faire la même chose dans le fichier de sérialiseurs: D Merci – flaire