Django templates, including page(s) that injects code into parent block - django

Is it possible to include a template (with include django template tag) within another template and "inject" some content to the page that includes (parent) through block tag, or something similar?
Let's say I have the following file structure within my project:
App/
(...)
templates/
base.html
index.html
_include1.html
_include2.html
_include3.html
_include4.html
Code for base.html:
<!DOCTYPE html>
<html>
<head lang="en">
(...)
</head>
<body>
<script type="application/javascript">
$(function () {
{% block extra_script %}
{% endblock %}
});
</script>
Code for index.html:
{% extends "base.html" %}
{% load static %}
(...)
<div class="row gutter">
<div>
{% include "_include1.html" with object=object%}
</div>
<div>
{% include "_include2.html" with object=object %}
</div>
<div>
{% include "_include3.html" with object=object %}
</div>
<div>
{% include "_include4.html" with object=object %}
</div>
</div>
And in each _include*.html I would like to call some specific JS function (for example), but I want to place it in the parents (index.html or base.html, doesn't matter in my case) extra_script block. I searched in the documentation, other questions and didn't find a way to do this with the include syntax.
I've done something similar but through extends tag. However I don't want to define a block in the index.html or base.html for each page that I need to include ({% bloc include_* %}.
So the solution that I have now (and works) is to define a script in each included page like this (_include1.html):
<div>
(...)
</div>
<script>
$(function () {
//Code that should be placed within parents script page (this is just an example)
var a = function (){
(...)
};
a();
});
</script>
However I think there's a better way to do this, by making use of django templates engine, and without having to define a block for each page that needs to be included. Also I would like to have all my js code in a single place (parents <script> tag) instead of being scattered all over the place (like it is with the presented solution).
Can anyone give some input or ideas towards this?
Thanks!

Try to use django-sekizai for that purpose.
With sekizai, you can define a JavaScript block just before the </body>:
{% render_block "js" %}
And then whenever you need to add JavaScript to that block, you write this:
{% addtoblock "js" %}
<script type="text/javascript">
// your JavaScript
</script>
{% endaddtoblock %}
If there are duplicates of the content in the {% addtoblock %} blocks, they will be used only once.

Related

Django template block from within template tag template

I have a template called base.html. This template contains a block called pagescripts at the bottom after jQuery has been loaded, like this:
<div class="container-fluid">
{% block content %}
{% endblock %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
<script defer src="https://use.fontawesome.com/releases/v5.0.10/js/all.js" integrity="sha384-slN8GvtUJGnv6ca26v8EzVaR9DC58QEwsIk9q1QXdCU8Yu8ck/tL/5szYlBbqmS+" crossorigin="anonymous"></script>
{% block pagescripts %}
{% endblock %}
Next, I have a template tag that is an inclusion tag for displaying a fancy-looking boostrap 4 card for a particular news article, like this:
#register.inclusion_tag('long_article_card.html', takes_context=True)
def show_long_card(context, article):
try:
contextForm = context['form']
except KeyError:
contextForm = None
return {'article':article, 'form': contextForm}
Now, within that long_article_card.html, I want to add a script to the pagescripts block from base.html. So, in long_article_card.html, I have this:
<div class="target">TARGET HERE</div>
<a class="dropdown-item" id="lean-vote-xl" href="#">Extreme Left</a>
{% block pagescripts %}
<script>
$(document).ready(function(){
$("#lean-vote-xl").on('click', function(){
$.ajax({
url:'/webproxy/v/?i=a&pk={{article.id}}&t=1&v=3',
type:'get',
dataType:'html',
crossDomain:true,
success:function(data)
{
var outputCard = "<div class=\"target\"><br><h2>That worked</h2></div>";
$(".target").html(outputCard);
},
error: function(data) {
var outputCard = "<div class=\"target\"><br><h2>Load Error</h2></div>";
$(".target").html(outputCard);
}
});
}); // end id_url_text
});
</script>
{% endblock %}
That template tag is then called from an article detail template called article/detail.html, which extends base.html.
{% extends 'base/base.html' %}
<div class="row">
{% show_long_card article %}
</div>
But that results in the javascript in long_article_card.html being rendered at the end of long_article_card.html, which means it is rendered before jQuery is loaded at the bottom of the page, therefore the script doesn't work because $ is not defined yet. What I need to happen is for the block pagescripts from long_article_card.html to be rendered at the very bottom of the page, essentially at the bottom of base.html. I need django to take the block pagescripts from long_article_card.html, pass it up to article/detail.html, and then article/detail.html to pass it up to base.html, then base.html includes it in its pagescripts block that is at the very bottom of base.html after jQuery is loaded.
I can't have long_article_card.html extend the article/detail.html because it causes a recursion error. Is there any way for long_article_card.html to add things to base.html's pagescripts block?
Thank you.
django-sekizai was built for this use case. It may be of use to you

DRY method to add a class to <body> in the base template?

This is the general structure of my base.html:
<html>
<head>
</head>
<body class="noscroll">
<nav class="navbar navbar-static-top navbar-dark bg-inverse">
</nav>
{% block content %}
{% endblock content %}
</body>
</html>
On certain pages, I want the noscroll class which is essentially overflow-y: hidden; but I also have pages that require the scroll. I could move the navbar into its own snippet and insert that, but such a method seems unsatisfactory. Or I could make a separate base_noscroll.html, but that may lead to inconsistencies, so I would have to nest two templates which again would become unsatisfactory.
Just add an override-able block with the default content:
<body class="{% block body_class %}noscroll{% endblock %}">
then the noscroll class is there, or you can override it in a template that extends base.html. Django template blocks can go nearly anywhere; they don't have to wrap entire HTML tags.
If you find yourself overriding this block a lot, you can always just add another template that extends base.html and does the override, then extend that:
# noscroll.html
{% extends 'base.html' %}
{% block body_class %}{# empty to override #}{% endblock %}
Then in subsequent pages you can extend either template. How much flexibility you need is always up to you.

Django static file inheritance

Perhaps I'm coming at my problem with a WordPress mindset but what i'd like to achieve is the notion of a parent/child theme for Django projects. I think I can solve the template issue by defining two template directories
TEMPLATE_DIRS = (
'/home/Username/webapps/django/child/templates',
'/home/Username/webapps/django/parent/templates',
)
But is there a way to achieve this with the static files? For example, we add a new feature to the parent, update the parent app which updates the templates along with adding some new javascript, LESS, and images.
You don't need to specify two template directories. There is a concept of parent and child templates. All child templates extends the parent:
base.html (we often use this name for parent)
<html>
<head>
<!-- Some css, js stuff goes here-->
{% block extra_head %}
<!-- A block where child templates add more css and js stuff if needed -->
{% endblock extra_head %}
</head>
<body>
{% block body %}
<!-- body content here -->
{% endblock body %}
</body>
</html>
And then child template will extend the base.html as:
child.html
{% extends "base.html" %}
{% block body %}
<h1>Hello!</h1>
{% endblock body %}

Template Django application extending template django project

I am quite a beginner in django and I need some advices.
I am trying as much as possible to create reusable django applications that will be used in several different projects. But I don't know how to proceed with templates.
If I have an application managing user, I think the template allowing to add, remove or list a user shall be located in the application and not in the project. Templates project should define headers, footers and general organisation (correct me if I'm wrong).
However, if I want to use template inheritance I will extend project template in my application template :
{% extends "base.html" %}
{% block content %}
...
{% endblock %}
So in developping my reusable application I make the assumption that my project will have a template called base.html with a block content, and in my mind this information should not be located at application level, but in project level. In some projects I will want to display users in block content, but not necessarily in others. I could want to display user information in several places in the same page for example...
How do you developp your application template to bypass this limitation ?
Thanks in advance,
Bill
What you are describing is probably best solved with custom template tags, specifically inclusion tags.
I would do a basic html template containing a header and a footer, and many reusable templates extending the basic one, containing the different layouts I would need. I would also create reusable components (tiles, datagrids...).
For the templates :
base.html
<!doctype HTML>
<html>
<head>
....
</head>
<body>
{% block content %}
</body>
</html>
3_columns.html
{% extends "project/base.html" %}
{% block content %}
<div class="line">
<div class="column">{% block col1 %}</div>
<div class="column">{% block col2 %}</div>
<div class="column">{% block col3 %}</div>
</div>
{% endblock %}
2_lines.html
{% extends "project/base.html" %}
{% block content %}
<div class="line">{% block line1 %}</div>
<div class="line">{% block line2 %}</div>
{% endblock %}
A basic custom component :
templatetags/custom.py
import django
from django.template.defaulttags import register
#register.inclusion_tag('components/custom.html')
def custom(params):
context = {
'a': params['a'],
'b': params['b']
}
return context
templates/components/custom.html
<div class="custom">
<label>{{ a }}
<input name={{ b }}
</label>
</div>
django-admin.py collectstatic
Read docs
Files are searched by using the enabled finders. The default is to look in all locations defined in STATICFILES_DIRS and in the 'static' directory of apps specified by the INSTALLED_APPS setting.

How to call several addOnLoad functions in dojo?

I'm trying to define several dojo elements from several (inherited) HTML pages , and each defines addOnLoad of his own, which causes only the latest function to be executed, since they are overridden.
Is there a way to overcome this problem?
Thanks.
You can use blocks to replace inherited elements
in template-base:
<head>
<script type="text/javascript" src=""></script>
{% block extra-header %}
#code default
...
{% endblock %}
</head>
in template:
{% block extra-header %}
{{ block.super }}
#replacement code
...
<script type="text/javascript" src=""></script>
{% endblock %}
for more information see https://docs.djangoproject.com/en/1.3/topics/templates/#template-inheritance