2012-05-21 10 views
5

mam dwa modele:Django - dostęp do Menedżera klucz obcy w django z szablonów

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) 

staram się dostać na żywo zdjęcia z informacjami o produktach szablonów.

próbował,

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

który nie działa i spojrzał na docs i nie mógł znaleźć przykłady. Czy można wywołać menedżera klucza obcego z szablonu? Czy powinienem wykonać funkcję w Modelu produktu, która zwraca zestaw zapytań o zdjęcie produktu?

Dziękuję.

Odpowiedz

23

Tak czy inaczej, sposób w jaki go używasz jest zły. Po prostu przekazujesz menedżera do pętli for, a nie zapytanie, które może być iterowane. Jednakże, photos sam jest "powiązanym menedżerem", a nie rzeczywistym modelem ProductPhoto, a powiązani menedżerowie są oparci na pierwszym wymienionym menedżerze lub objects (domyślny menedżer).

Ponieważ zdefiniować live, ale nie również zdefiniować objects, w rzeczywistości nie mają menedżera objects na tym modelu, to znaczy to nie powiedzie: ProductPhoto.objects.all(). Pamiętaj, że jeśli zdefiniujesz niestandardowego menedżera w swoim modelu, Django nie będzie już automatycznie dodawać jednego o nazwie objects.

Dobrą wiadomością jest to, że ponieważ live to domyślny menedżer teraz, można go używać jak:

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

I, dostaniesz tylko obiekty „na żywo”. Zła wiadomość jest taka, że ​​złamie to wiele innych rzeczy, które zależą od domyślnego menedżera będącego pełną kolekcją obiektów (na przykład admin). W zasadzie ukrywasz blok obiektów "nieżywych".

Co trzeba mieć to:

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() 

Uwaga, objects jest definiowana ręcznie i to pierwsze, co oznacza, że ​​pozostanie domyślny menedżer. Jednak to nie pozwala już na użycie menedżera live w szablonie. Ogólnie rzecz biorąc, na coś takiego, to najlepiej po prostu użyć jednego menedżera i dodać metodę do niego wrócić obiektów „na żywo”:

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) 

Tutaj jesteśmy rzeczywiście instacji zarówno QuerySet i Manager. Umożliwi to podłączenie się do dowolnego miejsca, a nie tylko z przodu. Na przykład, gdybyś miał niestandardowego menedżera bez niestandardowego zestawu zapytań, mógłbyś wykonywać tylko ProductPhoto.objects.live().filter(...), a nie ProductPhoto.objects.filter(...).live().

Więc, następnie dodać, że do modelu jako objects (zajmując miejsce domyślnego jeden Django dostarcza):

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

    objects = ProductPhotoManager() 

I wreszcie będziesz mógł używać go w szablonie:

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

Dziękuję Chris za najlepszą odpowiedź i dokładne wyjaśnienie. Dużo się nauczyłem. – DavidL

+5

Metoda 'get_query_set' zostaje zmieniona na' get_queryset' w Django 1.6. – allcaps