Tengo una aplicación django que se usa para la anotación donde guardo información sobre las anotaciones de imágenes en el modelo BiomarkerAnnotations a través de una relación de muchos a muchos. Hago un seguimiento de qué usuarios han completado la anotación de la imagen con el campo annotated .
from django.contrib.auth.models import User class Biomarker(models.Model): name = models.CharField(max_length=256) description = models.CharField(max_length=1024) class Image(models.Model): number = models.IntegerField(default=0) absolute_path = models.CharField(max_length=2560) biomarkers = models.ManyToManyField(Biomarker, through='BiomarkerAnnotations', related_name="biomarker_annotations") annotated = models.ManyToManyField(User, related_name="annotated_by") class BiomarkerAnnotations(models.Model): _image = models.ForeignKey(Image, on_delete=models.CASCADE) biomarker = models.ForeignKey(Biomarker, on_delete=models.CASCADE) user = models.ForeignKey(User, null=True,on_delete=models.SET_DEFAULT, default=1)Me gustaría crear una vista que devuelva, para un usuario específico (el que envía la solicitud), cuántas imágenes ha anotado y cuántas quedan por anotar. Hasta ahora he llegado a este punto, pero parece que no funciona: el recuento total devuelto por la consulta es mayor que el recuento de imágenes.
class AnnotStatsSerializer(serializers.ModelSerializer): annotations = serializers.IntegerField() count = serializers.IntegerField() class Meta: model = Image fields = ("count", "annotations") class AnnotatedStatsViewSet(viewsets.ReadOnlyModelViewSet): queryset = Image.objects.all() serializer_class = AnnotStatsSerializer def get_queryset(self): queryset = self.queryset user_object = self.request.user project_id = self.request.query_params.get('project', None) if project_id is None: raise Http404 queryset = queryset.annotate(annotations=Case(When(annotated__id__exact=user_object.id, then=Value(1)), default=Value(0), output_field=IntegerField())) \ .values('annotations').annotate(count=Count('annotations')).order_by('annotations') \ .values('count', 'annotations') return querysetCualquier ayuda apreciada.
Puedes trabajar con:
annotated_images = Image.objects.filter( biomarkerannotations__user=user_object ) .count() images_todo = Image.objects.exclude( biomarkerannotations__user=user_object ) .count() para obtener el número de annotated_images e images_todo .
o si está trabajando con la relación annotated de muchos a muchos:
annotated_images = Image.objects.filter( annotated=user_object ) .count() images_todo = Image.objects.exclude( annotated=user_object ) .count()Podemos dejar que esto funcione con un conjunto de usuarios con:
from django.db.models import Count, OuterRef, Subquery, Value User.objects.annotate( tagged=Count('annotated_by'), not_tagged=Subquery( Image.objects.exclude( annotated=OuterRef('pk'), ).values(foo=Value(None)).values( total=Count('pk') ).order_by(Value(None)) ) )Esto produce una consulta que se parece a:
SELECT auth_user.*, COUNT(app_name_image_annotated.image_id) AS tagged ( SELECT COUNT(V0.id) AS total FROM app_name_image V0 WHERE NOT EXISTS ( SELECT (1) AS a FROM app_name_image_annotated U1 WHERE U1.user_id = auth_user.id AND U1.image_id = V0.id LIMIT 1 ) ) AS not_tagged FROM auth_user LEFT OUTER JOIN app_name_image_annotated ON (auth_user.id = app_name_image_annotated.user_id) GROUP BY auth_user.*