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.