Django - filtering on related objects Django - filtering on related objects django django

Django - filtering on related objects


The filter method is for filtering which objects are returned based on the specified criteria, so it's not what you want here. One option is to do a second query to retrieve all ratings for given Event objects for the current User.

Models:

import collectionsfrom django.db import modelsclass RatingManager(models.Manager):    def get_for_user(self, events, user):        ratings = self.filter(event__in=[event.id for event in events],                              user=user)        rating_dict = collections.defaultdict(lambda: None)        for rating in ratings:            rating_dict[rating.event_id] = rating        return rating_dictclass Rating(models.Model):    # ...    objects = RatingManager()

View:

events = Event.objects.all()user_ratings = Rating.objects.get_for_user(events, request.user)context = {    'events': [(event, user_ratings[event.id]) for event in events],}

Template:

{% for event, user_rating in events %}  {% if user_rating %} ... {% endif %}{% endfor %}


In addition to S.Lott's suggestion, you may consider using select_related() to limit the number of database queries; otherwise your template will do a query on each event's pass through the loop.

Event.objects.all().select_related(depth=1)

The depth parameter is not required, but if your other models have additional foreign keys it will limit the number of joins.


To make best use of Django, you have to avoid trying to do joins.

A "left outer join" is actually a list of objects with optional relationships.

It's simply a list of Events, Event.objects.all(). Some Event objects have a rating, some don't.

You get the list of Events in your view. You handle the optional relationships in your template.

{% for e in event_list %}    {{ e }}    {% if e.rating_set.all %}{{ e.rating_set }}{% endif %}{% endfor %}

is a jumping-off point.