Django reverse lookup of foreign keys
Asked Answered
M

4

111

I have a venue, this venue has many events happening there. My models look like this:

class Venue(models.Model):
    title = models.CharField(max_length=200)
    date_published = models.DateTimeField('published date',default=datetime.now, blank=True)
    venue_latitude = models.CharField(max_length=200)
    venue_longitude = models.CharField(max_length=200)
    venue_address = models.CharField(max_length=200)
    venue_city = models.CharField(max_length=200)
    venue_state = models.CharField(max_length=200)
    venue_country = models.CharField(max_length=200)
    description = models.TextField()
    def __unicode__(self):
        return u'%s' % (self.title)

class Event(models.Model):
    title = models.CharField(max_length=200)
    date_published = models.DateTimeField('published date',default=datetime.now, blank=True)
    date_start = models.DateTimeField('start date')
    date_end = models.DateTimeField('end date')
    def __unicode__(self):
        return self.title
    description = models.TextField()
    price = models.IntegerField(null=True, blank=True)
    venue = models.ForeignKey(Venue)

I'd like to display all the events that are happening at a certain venue. How can I do that? My current view looks like:

def detail(request, venue_id):
    venue = get_object_or_404(Venue, pk=venue_id)
    return render(request, 'venue-detail.html', {'venue': venue})
Malfunction answered 9/3, 2013 at 3:43 Comment(2)
What module do these fields relate too description = models.TextField()?Electrobiology
Actually, these two models are each in their own app, I just posted them together to explain the point :)Malfunction
S
176

You can use events = venue.event_set to go the other way.

Note that venue.event_set is a manager object, like Event.objects, so you can call .all, .filter, .exclude and similar on it to get a queryset.

See the Django documentation

Seljuk answered 9/3, 2013 at 4:41 Comment(7)
Great! THanks for that. However, If I want to iterate over the events (for i in events) I'm getting "'RelatedManager' object is not iterable"Malfunction
How did you change it to QueryObject ?Prophase
@Prophase venue.event_set.all() or venue.event_set.filter(), usually.Rebhun
If anyone stills sees the error AttributeError: 'Foo' object has no attribute 'bar_set', you might want to check if related_name is set on the ForeignKey/OneToOneField/ManyToManyField of the child model (Bar) referencing the parent model (Foo).Diandrous
Will this lookup be fast ? should he add foregin key to Venue ? will it make it faster ?Hughett
Note that if a "related_name" has been set on the foreign key def, you do not need to append "_set".Thibeault
Be aware that setting related_name="+" on the ForeignKey will cause this to not be possible (source).Bireme
L
10

To those who have "'RelatedManager' object is not iterable"

Add all to retrieve the elements from the manager.

{% for area in world_areas.all %}

https://mcmap.net/q/168128/-39-relatedmanager-39-object-is-not-iterable-django (cannot add this in comment to the first answer)

Lubin answered 20/5, 2015 at 11:44 Comment(2)
You just saved my day link.Corcyra
I was about to create mess in my models before I found this :DDisastrous
Q
7

Go the other way round. Use Event model.

def detail(request, venue_id):
    venue = Event.objects.filter(venue__id=venue_id)
    return render(request, 'venue-detail.html', {'venue': venue})

PS: I have never used get_object_or_404(). Modify code accordingly.

Quaternity answered 9/3, 2013 at 3:51 Comment(6)
So what can I use in my template to display the venue title and all the events happening at this venue?Malfunction
in the template use {{ event.venue.title }} or as per your variables {{ venue.venue.title }} :) {% for i in venue %} {{ i.venue.title }}Quaternity
I get that, but how do I display all the events happening at this venue?Malfunction
the filter returns an array containing all the events that happen at the venue.loop over the array in the templates using the forQuaternity
venue = Event.objects.filter(venue__id=venue_id) I think this expression will return QuerySet of Event object instead of Venue object.Didactic
@Didactic read the question being asked.Assembly
A
1

You can use venue.event_set.all() to get all the events that are happening at a certain venue as shown below:

def detail(request, venue_id):
    venue = get_object_or_404(Venue, pk=venue_id)
    events = venue.event_set.all() # Here
    return render(request, 'venue-detail.html', {'events': events})
Arvy answered 21/7, 2023 at 18:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.