2013-02-02 2 views
0
# models.py 
class Gallery(models.Model): 
    images = models.ManyToManyField(Image, null=True, blank=True) 

class Image(models.Model): 
    image = models.ImageField() 


# views.py 
class GalleryIndex(ListView): 
    model = Gallery 

J'ai besoin d'obtenir une vignette pour chaque galerie, ce qui est très première/dernière/quelle que soit l'image. Comment LIMITER l'image par 1 pour n'importe quelle galerie en tant qu'attribut personnalisé (pour ne pas surcharger Gallery.images) sans appeler la deuxième requête SQL?Django ORM m2m limite à 1

Répondre

0

Je aurais dû mieux lire docs. API QuerySet standard ne peut pas gérer ces cas de manière efficace (annotate() génère la clause GROUP BY pour chaque champ parent qui est lent) donc je viens avec la méthode extra() et sous-requête brute.

class GalleryIndex(ListView): 
    queryset = Gallery.objects.extra(select={'thumb': 
     """ 
     SELECT "image" 
     FROM "app_image", "app_gallery_images" 
     WHERE (
      "app_gallery"."id" = "app_gallery_images"."gallery_id" 
      AND "app_gallery_images"."image_id" = "app_image"."id" 
     ) 
     AND "app_image"."image" IS NOT NULL 
     LIMIT 1 
     """ 
    }) 

Ce queryset faire exactement ce que je voulais, depuis SorlImageField (et ImageField) a besoin que le nom de fichier pour représenter la vignette dans les modèles.

0

Un grand nombre à de nombreux actes comme un descripteur pour une queryset normale, de sorte que vous pouvez faire my_gallery.images.all()[0] pour limiter la requête à 1.

+0

Cela ne fonctionne que par galerie, mais pas pour tous ... Je me trompe? – mktums

0

Je ne pense pas que je comprends bien ce que vous voulez faire, mais est-ce que le code ci-dessous ne fonctionne pas pour vous?

class Gallery(models.Model): 
    images = models.ManyToManyField(Image, null=True, blank=True) 

    def get_thumb(self): 
     return self.images.all()[0] 

Ou peut-être autre concept:

class Gallery(models.Model): 
    images = models.ManyToManyField(Image, null=True, blank=True) 
    thumbnail = models.ImageField() 

    def save(self, *args, **kwargs): 
     self.thumbnail = self.images.all()[0].image 

(une exception attrapant ici nécessaire si)

+0

Je souhaite sélectionner les galeries et leur première image comme attribut personnalisé dans une seule requête SQL. Le premier exemple génère toujours des requêtes + N (où N est le nombre de galeries). Le deuxième exemple ne peut pas exister dans mon cas en raison de la logique personnalisée pour la sélection des vignettes ... – mktums

+0

Alors décrivez votre sélection de vignettes personnalisées ... – aherok

+0

Ce n'est même pas la sélection, plutôt que de peupler les modèles 'Image' et' Gallery' sont totalement indépendants et séparés (C'est pourquoi le champ 'images' est nullable). J'ai réduit les requêtes SQL à deux en fournissant 'queryset = Gallery.objects.prefetch_related ('images'). All()' pour voir la classe ... Mais encore, c'est 2 requêtes, pas une. – mktums

Questions connexes