2012-05-21 10 views
5

Ho due modelli:Django - accedere alla Gestione di chiave esterna da modelli Django

class Product(models.Model): 
    name = models.CharField(max_length=255) 

class ProductPhoto(models.Model): 
    product = models.ForeignKey('Product', related_name='photos') 
    is_live = models.IntegerField(choices=LIVE_CHOICES, default=1) 

    live = LiveManager() 

class LiveManager(Manager): 
    def get_query_set(self): 
     return super(LiveManager, self).get_query_set().filter(is_live=1) 

Sto cercando di ottenere foto dal vivo da modelli di dettaglio del prodotto.

Provato,

{% for photo in product.photos.live %} 

che non funziona e guardò docs e non riusciva a trovare esempi. È possibile chiamare il manager della chiave esterna da un modello? Devo fare una funzione nel modello di prodotto che restituisce la foto del prodotto queryset?

Grazie.

risposta

23

Bene, il modo in cui lo si utilizza è sbagliato, comunque. Passeresti semplicemente il gestore nel ciclo for, non un queryset che potrebbe essere ripetuto. Tuttavia, photos è esso stesso un "gestore correlato", non il modello effettivo ProductPhoto e i relativi gestori sono basati sul primo gestore elencato o su objects (il gestore predefinito).

Dal momento che, si definisce live, ma non anche definire objects, in realtà non si dispone di un objects responsabile su questo modello, vale a dire il questo fallirà: ProductPhoto.objects.all(). Ricorda, se definisci un gestore personalizzato sul tuo modello, Django non aggiungerà più automaticamente uno denominato objects.

La buona notizia è che, poiché live è il manager di default ora, è possibile utilizzarlo come:

{% for photo in product.photos.all %} 

E, si otterrà solo gli oggetti "dal vivo". La cattiva notizia è che questo interromperà molte altre cose che dipendono dal gestore predefinito che è la raccolta completa di oggetti (ad esempio l'amministratore). Stai essenzialmente nascondendo il blocco di oggetti "non live".

Che cosa si dovrebbe avere è:

class ProductPhoto(models.Model): 
    product = models.ForeignKey('Product', related_name='photos') 
    is_live = models.IntegerField(choices=LIVE_CHOICES, default=1) 

    objects = models.Manager() 
    live = LiveManager() 

noti che objects è definito manualmente e è prima, il che significa che rimarrà il manager di default. Tuttavia, ciò non consente più di utilizzare il gestore live nel modello. In generale, per qualcosa di simile, è meglio utilizzare solo un unico gestore e aggiungere un metodo ad esso per restituire gli oggetti "dal vivo":

class ProductPhotoQuerySet(models.query.QuerySet): 
    def live(self): 
     return self.filter(is_live=1) 

class ProductPhotoManager(models.Manager): 
    use_for_related_fields = True 

    def get_query_set(self): 
     return ProductPhotoQuerySet(self.model) 

    def live(self, *args, **kwargs): 
     return self.get_query_set().live(*args, **kwargs) 

Qui, in realtà stiamo sottoclasse sia QuerySet e Manager. Ciò ti consentirà di mettere in catena live ovunque anziché solo nella parte anteriore. Ad esempio, se hai appena avuto un gestore personalizzato senza un queryset personalizzato, potresti solo eseguire ProductPhoto.objects.live().filter(...) e non ProductPhoto.objects.filter(...).live().

Così, poi si aggiunge che al vostro modello come objects (prendendo il posto di quella di default Django fornisce):

class ProductPhoto(models.Model): 
    product = models.ForeignKey('Product', related_name='photos') 
    is_live = models.IntegerField(choices=LIVE_CHOICES, default=1) 

    objects = ProductPhotoManager() 

E, infine, sarete in grado di usarlo nel modello:

{% for photo in product.photos.live %} 
+2

Grazie Chris per la migliore risposta e la spiegazione approfondita. Ho imparato molto. – DavidL

+5

Il metodo 'get_query_set' viene rinominato in' get_queryset' in Django 1.6. – allcaps