Display M2M Data in Template

Hi again folks,

I´m getting better in solving my programming problems in Django every day but one thing I still am always stumbling about is dealing with M2M-Relationsships.

Let’s take these models:

class Rooms(models.Model):

    room = models.CharField(max_length=25, unique=True)

class Keys(models.Model):

    key = models.CharField(max_length=25, unique=True)
    room = models.ManyToManyField(Rooms, through='LockingAuthorisations')

class LockingAuthorisations(models.Model):

    key = models.ForeignKey(Keys, null=True, blank=True, on_delete=models.CASCADE)
    room = models.ForeignKey(Rooms, null=True, blank=True, on_delete=models.RESTRICT)

Now I’m looking for a good way to display the data in a template-table.

if i simply use

key_list = LockingAuthorisations.objects.all()
context['authorisations'] = key_list

I can display the data with the usual for-loop in template but get a list with pairs of key and room.
Instead of this, i would like to display a distinct list of all keys on the left and a comma-separated row of the corresponding rooms on the right… ?

This is covered in the Many-to-many relationship docs. (Using a defined “through” table does not affect the availability of the regular M2M API.) For each Room you can retrieve the set of related Key and convert that set to a comma-separated string.

Hi Ken,
of course I know the page you have kindly linked. But either I am too silly to get the point or it is really not telling me how to deal with displaying the M2M data in template. This thread is not about dealing with the data in database, but only about displaying M2M-Data in a user-friendly way in templates. For this purpose, I didn’t find a clue in the Django docs, otherwise I would not have started the thread :wink:

I apologize if I’ve missed the gist of the question.

To clarify then, what aspect of this are you looking for?

You mentioned above:

So I’m envisioning something like this:

| ---------- | ----------------------------------------------------|
|    room    |  keys                                               |
|    101     |  a253, a537, a418                                   |
|    102     |  a104, a641, a317                                   |
| ---------- | ----------------------------------------------------|

Is that correct?

If so, ignore the M2M relationship for a moment.

Assume that you had an additional column on Room called capacity, such that Room now looks like this:

How would you create a template to only display the room and capacity in the style above?

Hi again…its more like vice versa:
Screenshot 2023-08-05 190230

But to cover your question:
would be in views.py something like

content['room_overview'] = Rooms.objects.all()

and then in template

{% for room in room_overview %}
    {{ room.room }} | {{ room.capacity }}
{% endfor %}

But i can not see how this deals with my problem ?

We’re getting there.

You’re creating an expression for Room that results in a queryset that gives you all Room.

Given the information referenced above regarding Many-to-Many relationships, and given any one instance of Room named room, what is the expression that will give you all of the Key related to that room?

You also know how to iterate over a collection in your template:
{% for room in room_overview %}

How do you think you would iterate over that collection of related Key?

And I just realized that I didn’t account for the perspective shift, but that doesn’t matter because access between entities in an M2M relationship is symmetrical. You can retrieve related entities from either direction.

Hi again,

the principles you are talking about are understood.
My problem was a very silly one: I simply didn’t know about some template tag switches:

Solved the problem meanwhile. If i go like

content['key_list'] = Keys.objects.all()

i can do

{% for key in key_list %}
 {{key.key}}  |  {{ key.room.all|join:", " }}
{% endfor %}

I simply didn’t know about the all option…

The all is not a “template tag switch”. It has nothing at all to do with the template. It is the queryset function - the exact same function as when you call Room.objects.all(). That is the key concept here that I think you’re missing.

The variable, key, is an object. The attribute room, is the many-to-many relationship manager as referenced in the docs above. The all is then a reference to the all method on that queryset.

Hi Ken,

I´m mabye not using the correct terminology for every part of code, as english is not my native language, so I am sorr, if this results in confusion…so i specify: I didnt know that i can use queryset-functions in this way within {{ }}`in templates. …so somehow it has at least something to do with templates :wink: