How to test for use of a django template block? - django

I would like to do the following:
{% if appnav %}
<hr />
<div id="appnav">
<ul class="tabs">
{% block appnav %}{% endblock %}
</ul>
</div>
{% endif %}
...however, testing for the present use of a block by templates further down the inheritance chain does not seem to work.
Is there some other conditional that might do this?

The template language doesn't provide exactly what you're looking for. Child templates can call the parent block with {{ block.super }}, but parent templates can't reference child templates.
Your best bet will probably be to write a custom template tag. There are two sections in the template manual to review.
First, Parsing until another block tag. This will give you the basics of how to parse.
Second, Parsing until another block tag and saving contents. By placing a block tag inside the custom tag, you could detect content and wrap it as appropriate. This should work, because I believe the inner block tag will be parsed first. If that doesn't work, subclass the existing block template tag provided by django to implement your special magic.

If you you are looking for an easy solution. You can hide the element as the default html.
<div id="appnav">
<ul class="tabs">
{% block appnav %}
<script>document.getElementById("appnav").style.display = "none"</script>
{% endblock %}
</ul>
</div>

Related

Django Templates - Best Practice in Avoiding Repeating Code that Require Different For Loops?

I'm creating a blog and have numerous pages that will display a list of articles. So, to avoid repeating that code, I'm trying to place it within a parent template that I can extend where needed.
The problem is I'll need a different for loop to display the article lists on each page/view. I figure the easiest approach would be to simply create blocks where I want the loop to start and close within the parent, then alter accordingly within each child.
However, Django doesn't allow you to close blocks that have an open for loop, despite closing the loop later in a different block.
My initial approach, in the parent, article_list.html:
<div class="row">
{% block loop_start %}
{% endblock loop_start %}
<div class="col-xs-12 col-sm-4">
<div class="card">
<a class="img-card">
<img class="img-fluid"src="../../static/{{ post.featured_image }}" />
</a>.... etc
I know I have to fix my src code.
Extends to child as:
{% block loop_start %}
{% for post in recent_articles %}
{% endblock loop_start %}
However, that doesn't work as noted above.
I've also tried wrapping the entire code for the article list in a block, extending it and performing the following within the child:
{% for post in recent_articles %}
{% block.super article_list %}
{% endblock article_list %}
{% endfor %}
That doesn't work either. Again, producing the same error as a block is closing before the loop ends. I've also tried closing the loop in the parent which doesn't work either.
Is there an easier way of going about this that I'm missing? I could pass the same variable to each view then implement the loop in the parent, but that seems janky and limiting.
What's best practice here?
You should take a look at a 'base.html' file. Take a look at this web-page: https://ultimatedjango.com/learn-django/lessons/create-the-project-base-template/
This will allow you to do {% extends 'base.html' %} all of which Django will handle.

Django custom template tags imitating {% block %} behavior

I was studying Django custom template tags and got a question about the possibilities of custom tags.
Assume I have a construction like
{% extends "base.html" %}
{% block leftmenu %}
{% spaceless %}
<div id="#leftmenu">
...
</div>
{% endspaceless %}
{% endblock %}
and I want to shorten it like
{% extends "base.html" %}
{% load myawesometags %}
{% myblock leftmenu %}
...
{% endmyblock %}
I can't just create custom tag adding <div> and removing spaces cause without {% block ... %} the content won't take it's place in the base template. So, the question is: is it possible to emulate standard Django blocks in custom template tags?
It is possible to write a block tag, however you should know that block tag and extends tag work together. If you look at the code for BlockNode and ExtendsNode you will see how they render the template contents together.
ExtendNode captures all the block nodes from current template and the parent template. These blocks are stored in render_context with key BLOCK_CONTEXT_KEY and with value as instance of BlockContext. All the blocks are added to BlockContext using method add_blocks which uses FIFO (first-in-first-out) queue. Once all the block nodes are stored ExtendNode then renders the parent template. This causes the BlockNode instances to be rendered in the parent template. BlockNode then picks the BlockContext from render_context to get the block data. And because of FIFO, when BlockNode pops the block object from BlockContext it picks the last block, i.e. the one it encounters last in the inheritance. That's what I understood when reading the code. If I missed something please correct me.
You may be able to inherit BlockNode to customize it to a certain degree.
It is possible, though I think this kind of template tag is not expected to be customized.
The easiest way is probably to inherit the BlockNode class to do what you want and (somewhat) copy the do_block() function https://github.com/django/django/blob/master/django/template/loader_tags.py#L172 to use your BlockNode.

Can I specify a multiline context variable/parameter when {% include %}ing a template?

I know that it is possible to set context variables when including a Django template from another template using
{% include "default_table.html" with table_header=table_header1 table_data=table_data1 %}
or
{% with "My data" as table_data %}
{% include 'default_table.html' %}
{% endwith %}
My issue with this is that both approaches don't let me define multiline variables (unless they are based on a previous multiline variable of course).
My specific usecase is this
<!-- widget.html -->
<div class="box">
<div class="title">{{ title }}</div>
<div class="title">{{ body }}</div>
</div>
and I'd like to be able to set a longer text for the body context variable. This will make is possible for me to reuse common widget HTML in various places. Can this be done?
I've been searching a bit on http://djangosnippets.org for an über {% with ... %} template tag, but haven't found any so far.
This Django snippet kinda solves my issue: http://djangosnippets.org/snippets/1860/ But I'd love to be able to set context variables instead of defining {% localblock step_ready_js %}{% endlocalblock %} in my widget HTML.

Django template inclusion

The template inheritance page on the django site doesn't really solve my problem (Django 1.2).
My base page looks like:
...
<div class="grid_12" id="content">
{% block content %}{% endblock %}
</div>
...
{% block javascript %}{% endblock %}
I have another template that defines content for these:
{% block content %}
animated sidebar
{% endblock %}
...
{% block javascript %}
alert('hello');
{% endblock %}
This is something like an animated sidebar, so I don't want to extend the base template since it's auxiliary to the main content of the page. If I just use "include", the entire thing is put where the "include" tag is placed - as a result the javascript doesn't run because it's included before one of its dependencies.
What's the best way to solve this?
EDIT
Sorry, I didn't make myself clear.
I have my content pages which render a template that extends "base.html". In "base.html" I want to include a sidebar template that needs to append blocks in "base.html". So I've tried just putting include "sidebar.html" into "base.html", but it just inserts the whole thing where the "include" tag is. What I want it to do is append the blocks in "base.html", which may themselves have been populated by "page.html".
Maybe it's important to say that "sidebar.html" is entirely static - i.e. there's no callable associated with it. So perhaps this question should really be "How can I include a static template into base.html so it will append to blocks in base.html regardless of the output of the actual view that processes the request?"
I think you mean you want to append to a block? You can put {{ block.super }} where you want the inherited content to go. e.g.:
{% block javascript %}
{{ block.super }}
alert('hello');
{% endblock %}
You should only use {% block foo %} tags to extend blocks in a base template, so I'm not clear what you mean when you say you don't want to extend it.
The code, as you've entered it, should render to
...
<div class="grid_12" id="content">
animated sidebar
</div>
...
alert(hello)
Unless you want to append the content (as in Matt's answer) it's not clear what you want to happen.
You shoud be using something like jQuery to trigger execution only after the page is fully loaded. Include jQuery library in the document header and then somewhere:
$(document).ready(function() {
//your code goes here
});

Template Inheritance in Django

I'm using Django 1.1, and I have this template, a base template, that all the other pages inherit from. It defines a bunch of things that are constant throughout pretty much all of the website, like this navbar:
<div id="navbar">
{% block navbar %}
Link 1
Link 2
Link 3
Link 4
Admin
{% endblock %}
</div>
But Django's default behavior within child templates is to have the child completely override blocks in the parent template. I've got this page here that doesn't necessarily have to override the navbar block, just add a few more entries to it that'll be specific to that page, but right now the only way I can see that happening is if I were to copy the navbar block from the parent and then include it in the template + my additions. Is there any other way that can be done?
Use {{ block.super }} in the child template to include the content from the parent block.
As Alasdair noted, {{ block.super }} allows you to use the value from the parent.
However, if you're finding you always need to do this, you should consider whether your blocks are granular enough. You should be able to lay them out in such a way that each block only defines the content it needs.
You can define nested blocks, so you could also do something like this:
<div id="navbar">
{% block navbar %}
Link 1
Link 2
Link 3
Link 4
Admin
{% block navbar-extra %}{% endblock %}
{% endblock %}
</div>
Templates that need to override the entire navbar could do so, while other templates could just override the "navbar-extra" block. IMO this is a little cleaner than using {{ block.super }} in situations where you know in advance where you'll need the extensibility; YMMV.
You don't have to define all blocks, so if you don't define navbar block in child page, it will use block content from parent.