【问题标题】:How to count items containing specific value in Django Many to Many relationship如何在 Django 多对多关系中计算包含特定值的项目
【发布时间】:2022-01-02 07:10:40
【问题描述】:

我有一个用于注释的 django 应用程序,我通过多对多关系将有关图像注释的信息保存到模型 BiomarkerAnnotations 中。我使用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)     

我想创建一个视图,为特定用户(发送请求的用户)返回他已注释的图像数量以及还有多少图像需要注释。到目前为止,我已经达到了这一点,但它似乎不起作用:查询返回的总计数大于图像计数。

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 queryset

任何帮助表示赞赏。

【问题讨论】:

  • 我不清楚为什么你的Image 模型中有两个 ManyToManyFields。
  • 用户可能在未完全完成注释的情况下使用一些生物标记对图像进行了注释。如果用户对象是annotated 字段的一部分,则不会将图像提供给用户进行注释。否则它将是并且biomarkers 注释预先填充了 biomarkers 字段的内容。对于这个问题,我会对完整的注释感兴趣,即annotated
  • 你见过infield lookup吗?另请参阅此答案stackoverflow.com/a/4508083/6143954

标签: python django


【解决方案1】:

您可以使用:

annotated_images = Image.objects.filter(
    biomarkerannotations__user=user_object
).count()
images_todo = Image.objects.exclude(
    biomarkerannotations__user=user_object
).count()

获取annotated_imagesimages_todo的数量。

或者如果您正在使用annotated 多对多关系:

annotated_images = Image.objects.filter(
    annotated=user_object
).count()
images_todo = Image.objects.exclude(
    annotated=user_object
).count()

我们可以让这组用户使用:

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))
    )
)

这会产生一个如下所示的查询:

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.*

【讨论】:

  • 谢谢。是否有可能在查询中执行所有操作?我正在寻找某种方法来简单地以[{"annotated": 1, "count": 70}, {"annotated": 0, "count": 85}] 的形式返回查询
  • @scandav:但我不明白为什么这里有多个项目:您想知道有多少Images 被用户注释/未注释。那是两个数字...
  • 因为问题比这要大一些,因为为了提出问题,我不得不简化它。这个想法是,我为每个用户获取这两个数字并为前端创建一个 API 视图。但我可能做得过火了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-11
  • 2013-02-19
  • 2014-12-03
  • 1970-01-01
  • 2017-07-16
  • 1970-01-01
  • 2020-08-16
相关资源
最近更新 更多