gek
gek

Reputation: 554

Multiple nested inheritance in templates

I have 4 models that need to be presented by chain inheritance each other. Like that:

├───GRANDPARENT1
│   ├───PARENT11
│   │   ├───CHILD111
│   │   └───CHILD112
│   └───PARENT12
│       ├───CHILD121
│       └───CHILD122
└───GRANDPARENT2
    ├───PARENT21
    │   ├───CHILD211
    │   └───CHILD212
    └───PARENT22
        ├───CHILD221
        └───CHILD222

I could do it by multiple {% for %} loops in a single template like it described here :

{% for grandparent in grandparents %}
    <p>{{ grandparent.title }}'s childs is:</p>
    {% for parent in grandparent.parent_set.all %}
        <p>{{ parent.title }}'s childs is:</p>
        {% for child in parent.child_set.all %}
             <p>{{ parent.title }}</p>
        {% endfor %}
    {% endfor %}
{% endfor %}

but i'd like to divide each class onto it's own template and bring them to the same form for clarity and ease of adding subsequently additional levels of nesting.

I'll show two models to show what problem is - Parent and Child:

I've tried to extend a parent template from base.html - it's works. But next, when i extend a child.html template from parent.html it outputs nothing.

models.py:

class Parent(models.Model):
    title = models.CharField(
        max_length=150,
    )
class Child(models.Model):
    title = models.CharField(
        max_length=150,
    )
    parents = models.ManyToManyField(
        Parent,
        blank=True
    )

update 2

In the database i have two objects of Parent class (PARENT1, PARENT2) and four objects of Child class (CHILD11, CHILD12,CHILD21,CHILD22). CHILD11 and CHILD 12 have PARENT1 in parents many-to-many relation; CHILD21 and CHILD22 have same on PARENT2, so it's has that structure:

├───PARENT1
│   ├───CHILD11
│   └───CHILD12
└───PARENT2
    ├───CHILD21
    └───CHILD22

views.py:

class ParentListView(ListView):
    model = Parent
    template_name = 'parent_list.html'
    context_object_name = 'parent_objects_list'


class ChildListView(ListView):
    model = Child
    template_name = 'child_list.html'
    context_object_name = 'child_objects_list'

urls.py

from django.urls import path

from .views import (
    ParentListView,
    ChildListView
)

urlpatterns = [
    path('parents/', ParentListView.as_view(), name='parents'),
    path('childs/', ChildListView.as_view(), name='childs'),
]

parent_list.html (updated) :

{% extends '_base.html' %}

{% block title %}Parents_list{% endblock title %}

{% block content %}
    {% for parent in parent_objects_list %}
        <div class="card">
            <div class="card-header">
                <span class="font-weight-bold">{{ parent.title }}</span>
            </div>
            <div class="card-body">
                {% block childs_block %}
                {% endblock childs_block %}
            </div>
        </div>
    {% endfor %}
{% endblock content %}

child_list.html

{% extends 'parent_list.html' %}

{% block title %}Childs_list{% endblock title %}

{% block childs_block %}
    {% for child in child_objects_list %}
        <div class="card">
            <div class="card-header">
                <span class="font-weight-bold">{{ child.title }}</span>
            </div>
        </div>
    {% endfor %}
{% endblock childs_block %}

-- that returns empty. I think i need to pass an argument with key into childs block to filter childs of certain parent but cannot find a way how to do that.

Upvotes: 2

Views: 614

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477676

Your ChildListView only sends a query of child_objects_list. This thus means that there is no parent_objects_list when you render the template, and hence the {% for ... %} loop will not loop.

You can thus pass a list of Parent object in your ChildListView, probably best with a prefetch_related on the child model:

class ChildListView(ListView):
    model = Parent
    template_name = 'child_list.html'
    context_object_name = 'parent_objects_list'
    queryset = Parent.objects.prefetch_related('child')

Then you can thus iterate over the child_set:

{% extends 'parent_list.html' %}

{% block title %}Childs_list{% endblock title %}

{% block childs_block %}
    {% for child in parent.child_set.all %}
        <div class="card">
            <div class="card-header">
                <span class="font-weight-bold">{{ child.title }}</span>
            </div>
        </div>
    {% endfor %}
{% endblock childs_block %}

Upvotes: 1

Related Questions