Django 泛型关系和 ORM 查询

发布于 2024-08-15 14:02:19 字数 1818 浏览 5 评论 0原文

假设我有以下模型:

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

编辑: Jarret Hardie 万岁!这是他本应显而易见的解决方案生成的 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

Say I have the following models:

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)

What's the most processor- and memory-efficient way to find all Articles that have at least one Image attached to them?

I've done this:

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

Which works, but besides being ugly it takes forever.

I suspect there's a better solution using raw SQL, but that's beyond me. For what it's worth, the SQL generated by the above is as following:

 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

EDIT: czarchaic's suggestion has much nicer syntax but even worse (slower) performance. The SQL generated by his query looks like the following:

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

EDIT: Hooray for Jarret Hardie! Here's the SQL generated by his should-have-been-obvious solution:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

相守太难 2024-08-22 14:02:19

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

Article.objects.filter(images__isnull=False)

这将为与多个 ImageArticle 生成重复项>s,但您可以使用 distinct() QuerySet 方法消除它:

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

Thanks to generic relations, you should be able to query this structure using traditional query-set semantics for reverse relations:

Article.objects.filter(images__isnull=False)

This will produce duplicates for any Articles that are related to multiple Images, but you can eliminate that with the distinct() QuerySet method:

Article.objects.distinct().filter(images__isnull=False)
瑶笙 2024-08-22 14:02:19

我认为你最好的选择是使用 聚合< /a>

from django.db.models import Count

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

I think your best bet would be to use aggregation

from django.db.models import Count

Article.objects.annotate(num_images=Count('images')).filter(num_images__gt=0)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文