2009-12-23 13 views
7

decir que tengo los siguientes modelos:Django Relaciones genéricos y ORM consultas

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) 

¿Cuál es la forma más en procesadores y la memoria-eficiente para encontrar todos los artículos que tienen al menos una imagen adjunta a ellos?

he hecho esto:

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

que funciona, pero además de ser fea se necesita siempre.

Sospecho que hay una mejor solución con SQL sin formato, pero eso me supera. Por lo que vale la pena, el SQL generado por el anterior es el siguiente:

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: sugerencia de czarchaic tiene una sintaxis mucho mejor pero aún peor rendimiento (más lento). El SQL generado por la consulta tiene el siguiente aspecto:

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: Hurra por Jarret Hardie! Aquí está el SQL generado por su debe-tener-sido-obvia solución:

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 
+0

¿Es esta su estructura modelo real, o hay toda una jerarquía de clases que no se está representando en su pregunta ejemplo por razones de simplicidad? Lo pregunto porque este ejemplo particular no requiere genéricos en absoluto. –

+0

No, esta es una estructura de modelo simplificada y simplificada. – hanksims

+1

Aunque su respuesta aceptada funciona bastante bien, tengo curiosidad por saber cuál sería la solución si necesitara algo más que 'al menos una imagen'. – czarchaic

Respuesta

6

Gracias a las relaciones genéricas, usted debería ser capaz de consultar esta estructura utilizando la semántica tradicionales de consulta de conjunto de las relaciones inversas:

Article.objects.filter(images__isnull=False) 

esto producirá duplicados para cualquier Article s que se relacionan con múltiples Image s, pero se puede eliminar con el método que distinct() QuerySet:

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

¡Creo que tenemos un ganador! Publicaré el SQL generado en otra edición, solo por completitud. Ran se iluminó rápidamente, sin embargo. is_null = False ... a veces las cosas más simples son solo mirarlo directamente a la cara. – hanksims

+0

Gracias Hanksims ... espero que funcione :-) Admito que no he mirado el SQL, así que definitivamente tengo curiosidad por ver eso. –

1

creo que la mejor opción sería utilizar aggregation

from django.db.models import Count 

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

Tiene más sentido, ¡pero en realidad funciona más despacio! Ver la edición. – hanksims

Cuestiones relacionadas