【问题标题】:Django Generic Relations and ORM QueriesDjango 通用关系和 ORM 查询
【发布时间】:2010-12-29 07:57:24
【问题描述】:

假设我有以下模型:

class Image(models.Model):
    image   = models.ImageField(max_length=200, upload_to=file_home)
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey()

class Article(models.Model):
    text = models.TextField()
    images = generic.GenericRelation(Image)

class BlogPost(models.Model):
    text = models.TextField()
    images = generic.GenericRelation(Image)

查找所有至少附有一张图片的文章的处理器和内存效率最高的方法是什么?

我已经这样做了:

Article.objects.filter(pk__in=Image.objects.filter(content_type=ContentType.objects.get_for_model(Article)).values_list('object_id', flat=True))

这行得通,但除了丑陋之外,它需要永远。

我怀疑使用原始 SQL 有更好的解决方案,但这超出了我的范围。值得一提的是,上面生成的SQL如下:

 SELECT `issues_article`.`id`, `issues_article`.`text` FROM `issues_article` WHERE `issues_article`.`id` IN (SELECT U0.`object_id` FROM `uploads_image` U0 WHERE U0.`content_type_id` = 26 ) LIMIT 21

编辑: czarchaic 的建议语法更好,但性能更差(更慢)。他的查询生成的 SQL 如下所示:

SELECT DISTINCT `issues_article`.`id`, `issues_article`.`text`, COUNT(`uploads_image`.`id`) AS `num_images` FROM `issues_article` LEFT OUTER JOIN `uploads_image` ON (`issues_article`.`id` = `uploads_image`.`object_id`) GROUP BY `issues_article`.`id` HAVING COUNT(`uploads_image`.`id`) > 0  ORDER BY NULL LIMIT 21

编辑:杰瑞特哈迪万岁!这是他的本应显而易见的解决方案生成的 SQL:

SELECT DISTINCT `issues_article`.`id`, `issues_article`.`text` FROM `issues_article` INNER JOIN `uploads_image` ON (`issues_article`.`id` = `uploads_image`.`object_id`) WHERE (`uploads_image`.`id` IS NOT NULL AND `uploads_image`.`content_type_id` = 26 ) LIMIT 21

【问题讨论】:

  • 这是您的实际模型结构,还是为了简单起见,您没有在问题示例中表示整个类层次结构?我问是因为这个特定的例子根本不需要泛型。
  • 不,这是一个精简和简化的模型结构。
  • 虽然您接受的答案效果很好,但我很想知道如果您需要“至少一张图片”以外的其他内容,解决方案是什么。
  • 嗯,这是我的特殊用例,所以我还没有真正考虑过。也许,比如,如果我想要所有至少有 2 张图片的文章?似乎您可能想要使用您概述的方法 - 但您必须从中缓存活着的 bejeezus,因为如果您的系统中有大量图像或文章,那将是一个长时间运行的查询.

标签: sql django orm generic-relationship


【解决方案1】:

由于通用关系,您应该能够使用传统的查询集语义来查询此结构以获取反向关系:

Article.objects.filter(images__isnull=False)

这将为与多个Images 相关的任何Articles 产生重复,但您可以使用distinct() QuerySet 方法消除它:

Article.objects.distinct().filter(images__isnull=False)

【讨论】:

  • 我想我们赢了!为了完整起见,我将在另一个编辑中发布生成的 SQL。不过,跑得很快。 is_null=False ... 有时最简单的事情只是盯着你的脸。
  • 感谢 hanksims...希望它成功 :-) 我承认我没有看过 SQL,所以很想知道。
【解决方案2】:

我认为你最好的选择是使用aggregation

from django.db.models import Count

Article.objects.annotate(num_images=Count('images')).filter(num_images__gt=0)

【讨论】:

    猜你喜欢
    • 2018-12-01
    • 2017-02-19
    • 1970-01-01
    • 2020-04-14
    • 2019-10-26
    • 2021-12-20
    • 2015-04-09
    • 1970-01-01
    • 2015-01-21
    相关资源
    最近更新 更多