I am trying to learn Django and have encountered a problem I can't figure out for the life of me. In this project I have an app called projects
. In this app I have one model called Projectinfo
and one called Buildingtypes
.
Every project can have one or more building types. What I am trying to do is to write a view that lists out all the projects with a commaseparated list of related building types.
Here's a simplified version of my two models:
class Buildingtypes(models.Model):
buildingtype = models.CharField(max_length=100)
def __str__(self):
return self.buildingtype
class ProjectInfo(models.Model):
project_number = models.CharField(max_length=12, blank=True)
project_name = models.CharField(max_length=120)
buildingtypes = models.ManyToManyField(Buildingtypes, default=[1])
def __str__(self):
return self.project_name
I made a view that looks like this:
from django.http import HttpResponse
from django.template import loader
from .models import ProjectInfo
def index(request):
myProjects = ProjectInfo.objects.all()
template = loader.get_template('projects/index.html')
context = {
'projects': myProjects,
}
return HttpResponse(template.render(context, request))
And the template:
{% if projects %}
{% for x in projects %}
{{ x.project_number }} | {{ x.project_name }} | {{ x.buildingtype }}
{% endfor %}
{% endif %}
Which resulted in this:
projectnumber | project name | building type
----------------------------------------------------------
101010 | project 1 | projects.Buildingtypes.None
202020 | project 2 | projects.Buildingtypes.None
Since that obviously failed I also tried this:
{% if projects %}
{% for x in projects %}
{{ x.project_number }} | {{ x.project_name }} | {% for y in x.buildingtypes %} {{ y.buildingtype }} {% endfor %}
{% endfor %}
{% endif %}
Which resulted in this:
projectnumber | project name | building type
----------------------------------------------------------
101010 | project 1 |
202020 | project 2 |
I made a query in MySQL just to show you what I am looking for. The following query gives me the result I want:
SELECT
project_number,
project_name,
GROUP_CONCAT(pb.buildingtype SEPARATOR ', ') AS buildingtypes
FROM
projects_projectinfo AS pp
JOIN
projects_projectinfo_buildingtypes AS ppb
ON
pp.id = ppb.projectinfo_id
JOIN
projects_buildingtypes AS pb
ON
ppb.buildingtypes_id = pb.id
GROUP BY
pp.id;
Result:
projectnumber | project name | building type
--------------------------------------------------------------------------------
101010 | project 1 | building type 1, building type 3
202020 | project 2 | building type 2, building type 5, building type 6
But how to convert this to a view?
I have made various attempts with select_related, prefetch_related, filter and what not, but I can't just can't figure it out.
You were pretty close, the last iteration of your template needs to be updated to be:
{% if projects %}
{% for x in projects %}
{{ x.project_number }} | {{ x.project_name }} | {% for y in x.buildingtypes.all %} {{ y.buildingtype }} {% endfor %}
{% endfor %}
{% endif %}
It does access the all()
method of m2m relation loading the values for you which you can iterate over.
if you want to read more about it: https://docs.djangoproject.com/en/5.0/ref/templates/language/#accessing-method-calls