Roy Prins
Roy Prins

Reputation: 3080

Pattern to organize related items into groups

Let me try to explain what I want to achieve by a small example application. It is a shopping list application that lets you add predefined Items to your ShoppingList as Groceries. The smart thing would be that every Item is related to a Store.

model

When I am done adding groceries to my shopping list, I should be able to see my shopping list with the groceries organized (grouped) by their Store. Something like:

template

How would I create a view and template to group and display this shopping list?

For example: this is how I would display the full inventory of all stores:

#views.py
store_list = Store.objects.all()

#template.html
{% for store in store_list %}
<div>{{store}}
    <ul>
    {% for item in store.item_set.all %}
        <li>{{item}}</li>
    {% endfor %}
    </ul>
</div>
{% endfor %}

That won't work for my shopping list, but I am really looking for something equally powerful / elegant....

Upvotes: 4

Views: 256

Answers (3)

Todor
Todor

Reputation: 16050

What about the built in regroup template tag?

{% regroup item.objects.all by store as store_groups %}

<ul>
{% for store_group in store_groups %}
    <li>{{ store_group.grouper }}
    <ul>
        {% for item in store_group.list %}
          <li>{{ item }}</li>
        {% endfor %}
    </ul>
    </li>
{% endfor %}
</ul>

Upvotes: 3

Graphics Noob
Graphics Noob

Reputation: 10070

Do the grouping in the backend of the view instead of the template.

In your view, create a dictionary like this:

sorted_groceries = {
    store1 : [item1, item2],
    store2 : [item3, item4],
}

which can be done with some code resembling this pseudo-code:

sorted_groceries = {}
for item in shopping cart:
    try:
        sorted_groceries[item.store].append(item)
    except KeyError:
        sorted_groceries[item.store] = [item]

then add it to your context and have your template look like this:

{% for store, items in sorted_groceries.items %}
<div>{{store}}
    <ul>
    {% for item in items %}
        <li>{{item}}</li>
    {% endfor %}
    </ul>
</div>
{% endfor %}

Upvotes: 2

PhoebeB
PhoebeB

Reputation: 8570

How about using ifchanged https://docs.djangoproject.com/en/1.7/ref/templates/builtins/#ifchanged

Assuming shopping_list is sorted by store:

{% for item in shopping_list %}
     {% ifchanged %}<h3>{{ item.store.name }}</h3>{% endifchanged %}
     {{ item.name }}
{% endfor %}

Upvotes: 1

Related Questions