Django:至少检索包含一张公共照片的所有图库

时间:2009-09-02 10:38:02

标签: python sql django django-models count

请原谅我丑陋的英语!)

想象一下这些非常简单的模型:

class Photo(models.Model):
    is_public = models.BooleanField('Public', default=False)

class Gallery(models.Model):
    photos = models.ManyToManyField('Photos', related_name='galleries', null=True, blank=True)

我需要选择包含至少一张公共照片的所有Gallery个实例(如果可能的话,添加包含公开照片数量的photos__count属性)。< / p>

我尝试了这个查询:

Gallery.objects.all()\
    .annotate(Count('photos'))\
    .filter(photos__is_public=True)

似乎没关系,但是: - 查询很奇怪 - 每个图库中添加的属性photos__count将包含此图库中的照片总数,而不是此图库中公开照片的数量。

我认为我需要的硬编码sql查询是:

SELECT `gallery`.* , COUNT(`gallery_photos`.`photo_id`) 
FROM `gallery` 
    INNER JOIN `gallery_photos` ON (`gallery`.`id` = `gallery_photos`.`gallery_id`) 
    INNER JOIN `photo` ON (`gallery_photos`.`photo_id` = `photo`.`id`) 
WHERE `photo`.`is_public` = True 
GROUP BY gallery.id ;

有什么想法来解决它吗?

谢谢! ; - )

4 个答案:

答案 0 :(得分:0)

这应该这样做:

修改,更新以添加计数:

SELECT `gallery`.*, 'a'.'count' 
FROM `gallery` 
inner join (
    select `gallery`.`id`, count(*) as count
    from `gallery_photos` 
    INNER JOIN `photo` ON (`gallery_photos`.`photo_id` = `photo`.`id`) 
    where `photo`.`is_public` = True
    group by `gallery`.`id`
) a on `gallery`.`id` = 'a'.'id'
WHERE `photo`.`is_public` = True 

答案 1 :(得分:0)

我会尝试:

Gallery.objects.filter(photos__is_public=True).annotate(Count('photos'))

我相信你的过滤器排序错误,但我没有设置你的模型来测试这个假设。

尝试第二个:

Gallery.objects.exclude(photos__is_public=False).annotate(Count('photos'))

这应该排除所有照片都没有公开的所有画廊,并返回一个是什么和不公开的数量。

答案 2 :(得分:0)

此?

Gallery.objects.filter(photos__is_public=True)\
               .annotate(Count('photos__is_public'))

答案 3 :(得分:0)

django文档位于

http://docs.djangoproject.com/en/dev/topics/db/aggregation/#order-of-annotate-and-filter-clauses

我的经验说明了以下问题:

Gallery.objects.filter(photos__is_public=True).annotate(Count('photos'))

会为您的图库提供至少一张公开的照片以及仅公开的照片。唯一的问题是它会排除没有公开照片的画廊,但听起来你并不关心这一点。你测试了上面的查询吗?

如果它仍然没有返回正确的数据,那么注释可能会改变返回的数据,因为它只返回所有公共的画廊。在这种情况下,您可以使用“额外”方法来获得所需的计数。

Gallery.objects.filter(photos__is_public=True).extra(select={
  "photo_count": """
  SELECT COUNT(`gallery_photos.id`)
      FROM `gallery_photos`
  WHERE `gallery_photos.gallery_id` `gallery.id AND
        `gallery_photos.is_public = True
  """})

Jason Christa的排除方法也可行。