Displaying a list by the catory the list items belong to.

Hi. This is my first time using Python and first time ever using a framework or OOP.

I’m working on a book keeping system. In the system there will be Ledgers, which belong to a COAGroup.

The model so far is:

class COAGroup(models.Model):
    Name = models.CharField(max_length=200)
    def __str__(self):
        return self.Name

class Ledger(models.Model):
    Name = models.CharField(max_length=200)
    COAGroup = models.ForeignKey(COAGroup, on_delete=models.CASCADE)
    Is_reconcilable = models.BooleanField(default=False)
    def __str__(self):
        return self.Name

I’m trying to create a view which lists all the Ledgers by their COAGroup. I’ve written the following view.py:

def showledgers(request):  
    COAGroups = COAGroup.objects.all()
    Ledgers = Ledger.objects.all()
    context = {
        "COAGroups":COAGroups,
        "Ledgers":Ledgers,
    }
    return render(request,"showLedgers.html",context)

I don’t know what to do next. I want to list the ledgers by their COAGroup as follows:

SOME COA GROUP
A ledger that belongs to the group
Another ledger
And another ledger

ANOTHER COA GROUP
A ledger that belongs to the second COA Group
And another

And so on…

@undiplomatic,

I think you can achieve this by using Django’s template tag {% regroup %}:

# view.py
def showledgers(request):
    ledgers = Ledger.objects.all()
    return render(request, "showLedgers.html", { 'ledgers': ledgers })

# template.html
{% regroup ledgers by COAGroup as coagroup_list %}

<ul>
{% for group, local_ledgers in coagroup_list %}
    <li>{{ group }}
        <ul>
        {% for ledger in local_ledgers %}
            <li>{{ ledger }}</li>
        {% endfor %}
        </ul>
    </li>
{% endfor %}
</ul>

More here: https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#regroup

I think there is a way to use something like GROUP BY inside your database query (by aggregating the results, for instance), but I don’t recall the right way of using it…

A COAGroup's ledges are available on the instance:

> group = COAGroup.objects.create()
> ledger = Ledger.objects.create(name="Fred", group=group)
> group.ledger_set  # This is an iterable containing the ledgers for your group.

In your template you would have a double loop:

{% for group in groups %}
  {{ group.name }}

  {% for ledger in group.ledger_set %}
   {{ ledger.name }}
  {% endfor %}
{% endfor %}

I would strongly recommend going through the Django tutorial which covers this in the second part: all docs, part 2. You will learn a lot!

If you want to be more efficient you can use prefetch_related which will minimise the number of queries (by fetching all the groups and their associated ledgers up front rather than on demand):

groups = COAGroup.objects.prefetch_related("ledger").all()

Also, since you mentioned you’re a first time Python user I thought I’d mention Python naming conventions. Generally classes are written with CapitalsLikeThis (as you have done) while functions and attributes are_lowercase_and_have_underscores_between_words. These are pretty universally used in new Python code so might want to adopt these conventions too. RealPython has a good article on this.

Definitely, @takkaria’s suggestion is way better than mine. :slight_smile: