Django универсальные отношения и запросы ORM

Скажите, что у меня есть следующие модели:

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, сгенерированный его should-have-been-obvious решением:

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
7
задан hanksims 23 December 2009 в 00:54
поделиться

2 ответа

Благодаря общим отношениям, Вы должны иметь возможность запрашивать эту структуру, используя традиционную семантику "запрос-набор" для обратных отношений:

Article.objects.filter(images__isnull=False)

Это приведет к созданию дубликатов для любых статей , которые связаны с множественными изображениями , но вы можете устранить это с помощью distinct() QuerySet метода:

Article.objects.distinct().filter(images__isnull=False)
6
ответ дан 7 December 2019 в 07:46
поделиться

Я думаю, что лучше всего было бы использовать агрегацию

from django.db.models import Count

Article.objects.annotate(num_images=Count('images')).filter(num_images__gt=0)
1
ответ дан 7 December 2019 в 07:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: