2012-05-21 22 views
5

У меня есть две модели:Джанго - доступ к менеджеру по внешнему ключу от Джанго шаблонов

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) 

Я пытаюсь получить живые фотографии с описанием товаров шаблонов.

Пробовал,

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

, который не работает и посмотрел на документы и не могли найти примеры. Можно ли вызвать менеджера внешнего ключа из шаблона? Должен ли я выполнять функцию в модели продукта, которая возвращает запрос на выборки продукта?

спасибо.

ответ

23

Ну, как вы его используете, так или иначе. Вы просто передаете менеджера в цикл for, а не в набор запросов, который можно было бы повторить. Однако photos сам по себе является «связанным менеджером», а не фактической моделью ProductPhoto, а связанные менеджеры основаны на первом указанном менеджере или objects (менеджер по умолчанию).

Поскольку вы определяете live, но также не определяет objects, вы на самом деле не имеют objects менеджер по этой модели, то есть это не получится: ProductPhoto.objects.all(). Помните, что если вы определяете пользовательский менеджер на своей модели, Django больше не будет автоматически добавлять один из них: objects.

Хорошая новость заключается в том, что, поскольку live является менеджером по умолчанию в настоящее время, вы можете использовать его так же, как:

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

И, вы получите только «живые» объекты. Плохая новость заключается в том, что это сломает много других вещей, которые зависят от менеджера по умолчанию, являющегося полным набором объектов (например, admin). Вы по существу скрываете блок «неживых» объектов.

То, что вы должны иметь это:

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

objects Обратите внимание, что определяется вручную и это первое, то есть он будет оставаться менеджером по умолчанию. Тем не менее, это больше не позволяет использовать ваш менеджер live в шаблоне. В общем, что-то вроде этого, то лучше всего использовать один менеджер и добавить метод к нему вернуться «живые» объекты:

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) 

Здесь мы фактически подклассов как QuerySet и Manager. Это позволит вам цепочки live где угодно, а не только спереди. Например, если у вас был пользовательский менеджер без пользовательского запроса, вы могли бы сделать только ProductPhoto.objects.live().filter(...), а не ProductPhoto.objects.filter(...).live().

Таким образом, вы затем добавить, что в вашей модели, как objects (занимает место по умолчанию один Django предоставляет):

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

    objects = ProductPhotoManager() 

И, наконец, вы будете иметь возможность использовать его в шаблоне:

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

Благодарим Криса за лучший ответ и подробное объяснение. Я многому научился. – DavidL

+5

Метод 'get_query_set' переименован в' get_queryset' в Django 1.6. – allcaps

Смежные вопросы