I have a model that looks like this:
class ListEntry(models.Model):
STATUS_CHOICES = (
('PL', _('Playing')),
('CO', _('Completed')),
('OH', _('On-hold')),
('DR', _('Dropped')),
('WA', _('Want to play')),
)
user = models.ForeignKey(User)
game = models.ForeignKey(Game)
status = models.CharField(_('Status'), max_length=2,
choices=STATUS_CHOICES)
In my views I'm filtering the entries by user like this:
class GameListByUserView(ListView):
model = ListEntry
template_name = 'game_list_by_user.html'
def get_queryset(self):
self.user_profile = get_object_or_404(User, username=self.kwargs['slug'])
return ListEntry.objects.filter(user=self.user_profile)
def get_context_data(self, **kwargs):
context = super(GameListByUserView, self).get_context_data(**kwargs)
context['user_profile'] = self.user_profile
return context
What I'm trying to do now is split this query (ListEntry.objects.filter(user=self.user_profile)
) into subgroups depending on the status
attribute, so the rendered template looks like:
UserFoo's list
=========================
Playing
Game 1
Game 2
Game 3
Completed
Game 4
Game 5
Game 6
I know I can do something like:
q = ListEntry.objects.filter(user=self.user_profile)
games_dict = {}
games_dict['playing'] = q.filter(status='PL')
games_dict['completed'] = q.filter(status='CO')
And so on, and iterate over the keys in the template. Or (in the template):
{% for s in status_choices %}
{% for entry in object_list %}
{% if entry.status == s %}
Render things
{% endif %}
{% endfor %}
{% endfor %}
But isn't there a better, optimized way to do this without hitting the database every time I get a subquery by status, and without iterating over the objects list multiple times?
You are looking for the regroup
filter
{% regroup object_list by status as games_list %}
<ul>
{% for game in games_list %}
<li>{{ game.grouper }}
<ul>
{% for item in game.list %}
<li>{{ item}}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
You might have to customize the way the elements render, but I will let you figure that out yourself.