user1136324
user1136324

Reputation: 211

Django: How to access a list of backward relationships in a view?

let's assume, I have a model called Chicken:

class Chicken(models.Model):
    name = models.CharField(max_length=30)

and I also have a model called Egg that has a ForeignKey to the Chicken-model:

class Egg(models.Model):
    chicken = models.ForeignKey(Chicken)
    layed_on = models.DateField(auto_add_now=True)

Now I want to create a view that contains a list of the all the chickens and the date when they layed their last egg.

I know how to get all eggs layed by a chicken, using something like this:

c = Chicken.objects.get(name='Henry')
e = c.egg_set.all()

But that doesn't really help, because I have a lot of chickens and I want to only get the date of their latest egg. I also don't know how to get that egg information into my view for easy access. In my view I would like to do something like this:

{% for chicken in chickens %}
    <p>{{ chicken.name }} layed is last egg on {{ chicken.last_egg }}</p>
{% endfor %}

This is probably a very basic question, but I'm just a beginner and I would greatly appreciate any help you can give. The Django documentation does not really help me in this case.

Upvotes: 1

Views: 178

Answers (2)

Francisco
Francisco

Reputation: 1382

I personally like to solve such a problem annotating methods in my models with the @property annotation.

An example: In your Chicken model, you would have a method like:

@property
def last_egg(self):
    return self.egg_set.order_by('-layed_on')[0]

And in your template, you could use it as a regular model field.

{{my_chicken.last_egg}}

I would additionally like to know if there are any issues about this solution, and what you guys think about it. Maybe we could make this question a nice talk about how to ellegantly solve this issue.

Hope it helps.

Upvotes: 0

mklauber
mklauber

Reputation: 1144

What you're looking for is django's annotation feature. Basically, you want to annotate each row in chicken with the Max of egg's layed_on field. Without a prompt right in front of me, I can't guarentee the exact statement below, but it should give you a starting point.

Edit your chicken model like this:

class Egg(models.Model):
    chicken = models.ForeignKey(Chicken, related_name='eggs')
    layed_on = models.DateField(auto_add_now=True)

from django.db.models import Max
Chicken.objects.annotate(last_egg=Max('eggs__layed_on'))

Upvotes: 4

Related Questions