moku
moku

Reputation: 4249

Extending a template thats already extended in Django

I'm trying to figure out if there is a way to extend a partial view into a view that already extends base.html.

Here is an example of what I'm trying to do:

my-template.html

{% extends 'base.html '%}

<div class="row">
  <div class="col-xs-12">
    <ul class="nav nav-tabs">
      <li role="presentation" class="active"><a href="#">Tab1</a></li>
      <li role="presentation"><a href="#">Tab2</a></li>
    </ul>
  </div>
</div>

<div>
{% block tab_content %}
{% endblock %}
</div>

partial1.html

{% extends 'my-template.html' %}

{% block tab_content %}
<h1>I'm partial 1</h1>
{% endblock %}

The my-template.html view has a url that is constructed like so:

url(r'^my-template/(?P<id>[0-9]+)/$', views.my_template_view, name='my-template')

in addition a context dict is passed into the my_template_view providing the id for the url.

I would like the for the user to click on a tab and for its corresponding partial to be rendered with a url like so:

url(r'^my-template/(?P<id>[0-9]+)/tab1/$', views.tab1_view, name='tab1-view')

but right now I'm getting a NoReverseMatch at /my-template/97/tab1/ which I'm assuming means that my tab1_view doesn't have access to the same context as the my_template_view and thus can't get the id to build the reverse of my url.

In template /partial1.html, error at line 0
Reverse for 'tab1_view' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['/my-template/(?P<id>[0-9]+)/tab1/$']

So, is there a way for me, at the very least, to pass along the context or the id so this works, or am i going about this in the entirely wrong way?

Upvotes: 3

Views: 2503

Answers (1)

cardonator
cardonator

Reputation: 396

The typical way to solve this is by using the include template tag, not by extending with a new template.

Here is the Django doc describing this.

You can even use a variable to define a dynamic template name that will be included based on logic in your view.

Little more clarification here:

You can also have the URL route direct to the same view and have the "tab" optionally passed in as a second parameter as so:

url(r'^my-template/(?P<id>[0-9]+)/(?P<tab_name>\w+)/$', views.my_template_view, name='my-template')
url(r'^my-template/(?P<id>[0-9]+)/$', views.my_template_view, name='my-template')

And your view would look something like:

def my_template_view(request, id, tab_name=None):
    if not tab_name:
        tab_name = "tab1"
    if tab_name == "tab1":
        partial = "tab1.django.html"
    elif tab_name == "tab2":
        partial = "tab2.django.html"
    return render("my-template.html", { 'partial': partial })

And on your template you would have:

{% include partial %}

Because the included template will have the same context, you will have access to any variables that were available in the original context as well.

EDIT 2020/09/04: As noted in a comment below, the above page no longer exists. I've updated the above link to the latest in the 1.11 branch, but for the latest version of Django (3.1 as of this edit) you can refer to the same doc here.

Upvotes: 6

Related Questions