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.
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 actualProductPhoto
model, and related managers are based off the first listed manager orobjects
(the default manager).Since, you define
live
, but do not also defineobjects
, you don't actually have anobjects
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 namedobjects
.The good news is that because
live
is the default manager now, you can use it just like: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:
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 yourlive
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: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 doProductPhoto.objects.live().filter(...)
and notProductPhoto.objects.filter(...).live()
.So, you then add that to your model as
objects
(taking the place of the default one Django provides):And, finally, you'll be able to use it in your template: