Django - accessing foreign key's Manager from django templates

django, django-managers, django-models, django-templates

Solution

Well, the way you're using it is wrong, anyways. You'd just be passing the manager into the for loop, not a queryset that could be iterated over. However, `photos` is itself a "related manager", not the actual `ProductPhoto` model, and related managers are based off the first listed manager or `objects` (the default manager).

Since, you define `live`, but do not also define `objects`, you don't actually have an `objects` manager on this model, i.e. the this will fail: `ProductPhoto.objects.all()`. Remember, if you define a custom manager on your model, Django will no longer automatically add one named `objects`.

The good news is that because `live` is the default manager now, you can use it just like:

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

And, you'll only get "live" objects. The bad news is that this will break a lot of other things that depend on the default manager being the full collection of objects (admin for example). You're essentially hiding the block of "non-live" objects.

What you should have is:

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

Notice that `objects` is defined manually and it's first, meaning it will remain the default manager. However, that then no longer allows you to use your `live` manager in the template. Generally, for something like this, it's best to just use a single manager and add a method to it to return "live" objects:

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)

Here, we're actually subclassing both QuerySet and Manager. This will allow you to chain `live` anywhere instead of just at the front. For example, if you just had a custom manager without a custom queryset, you would only be able to do `ProductPhoto.objects.live().filter(...)` and not `ProductPhoto.objects.filter(...).live()`.

So, you then add that to your model as `objects` (taking the place of the default one Django provides):

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

    objects = ProductPhotoManager()

And, finally, you'll be able to use it in your template:

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

Problem

I have two models: ``` 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) ``` I am trying to get live photos from product detail templates. Tried, ``` {% for photo in product.photos.live %} ``` which doesn't work and looked at docs and couldn't find examples. Is it possible to call the foreign key's manager from a template? Should I make a function in Product model that returns product photo queryset? Thank you.

Original source