Django how to dynamically add js and CSS in sub templates? - django

I am new to Django.
I have a basic template set up where I have base.html using {% block body %}{% endblock %} to include a sub template of index.html and test.html where they have {% extends 'base.html' %} at the top.
The base.html template includes Bootstrap. It is where the CSS and JS are included. index.html needs to include select2 but test.html does not.
I could use blocks here to solve my problem (adding CSS and JS block to base.html) but I see that as getting very messy very quickly.
Is there anyway I can use assets in Django to create a select2 asset and have that called in the sub template to register the needed JS and CSS with the parent template?
All I see is compression and numerous searches have, so far, come up empty.

It okay to add 2 more blocks in your base.html:
<some css>
{% block additional_css %}
{% endblock additional_css %}
...
<some js>
{% block additional_js %}
{% endblock additional_js %}
and the override them in any page extended from base.html:
{% extends "base.html" %}
{% block additional_css %}
<link rel="stylesheet" type="text/css" href="{% static 'css/bootstrap-datetimepicker.min.css' %}">
{% endblock additional_css %}
...
{% block additional_js %}
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.0/moment.min.js"></script>
<script type="text/javascript" src="{% static 'js/bootstrap-datetimepicker.min.js' %}"></script>
{% endblock additional_js %}
That is a good practice because in this case the scripts will load in the very end and if some of your added script require for example JQuery, you won't face any problems.
It doesn't make the code messy, it's flat and easy to explain. It's better to think how not to make JS messy, and as you pointed, there are several ways to do this, on of them is to compress all the JS.

There are a few options that I can think of
The first is the ugly way that involves an {% if include_my_js_please %} in the base.html that is ignored if the context variable isn't included and for obvious reasons, arguments would be had if this made its way into our production code
The second is the way that you say can get very messy but its the way we do it and works very well for us, we have an {% extended_head %} and {% extended_footer %} in the base.html and as you'd expect we use this sparingly when required. Although we are very careful about what is included into this.
The third way is to just include everything in the base.html and only worry about it when it actually becomes a problem (I can see both the pros and con's of this)
and the fourth and final way I can think of is to make use of the Forms Media class
Django allows you to associate different files – like stylesheets and scripts – with the forms and widgets that require those assets. For example, if you want to use a calendar to render DateFields, you can define a custom Calendar widget. This widget can then be associated with the CSS and JavaScript that is required to render the calendar. When the Calendar widget is used on a form, Django is able to identify the CSS and JavaScript files that are required, and provide the list of file names in a form suitable for easy inclusion on your Web page.
Obviously this doesn't work in all use cases

Related

Django asset manager for Views or template tags?

I come to Django having used the Yii2 PHP framework. One of the good features about that is it allows you to create asset files for CSS and JS which are then loaded into the base layout file at runtime. This allows you to keep the base template clean of CSS and JS markup within the head and at the bottom of the HTML document. The CSS and JS files you specify in the asset file are automatically placed in the correct position in the document and you can also specify dependencies if needed.
At the moment, with Django I am having to edit the base.html file manually which is not ideal.
I know you can use the Media class for forms, and in admin.py, which does a similar job. However, what I would like to do is to something like this (for example) in inclusion template tags or in a class based view perhaps.
Is this possible?
Many thanks!
UPDATE
Here is a similar question Is it possible to use django's custom template tags to insert code in other blocks in the template?
do you find block tag?
base.html
<head>
{% block extra_css %}{% endblock %}
<head>
view.html
{% extends 'base.html' %}
{% block extra_css %}
<link rel="stylesheet" href="YOUR URL">
{% endblock %}

Best practice for Django components

Django provides a means of collecting assets into its Widget framework, and in turn using a form to present it, but how about doing this outside the forms framework?
For example, let's say I just want a simple, self-enclosed web component that requires two .js files, a CSS file, a template, and is backed by a view to generate some data. This isn't a "form" because it's not intended to collect input. Rather, assume it's, say, a customized scrollbar. I can't seem to find the right match for this usage pattern even though it seems common and straight-forward.
To do this now seems to mean adding the CSS to the top-level template; the JS to the template (or script tags arbitrarily in the included document); and then rendering the form as an include. But wouldn't it be easier to have something like:
class ScrollBar(...):
template_name = ...
class Assets:
...
and then rendering it via a templatetag, but with the ability for a context processor or other hook to extract the assets into their appropriate places in the page?
Something like:
index.html:
<html>
<head>
...
{% compressed_css %}
</head>
<body>
...
{% compressed_js %}
{% block content %}
{% endblock %}
</body>
scrollbar-using-page.html
{% extends "index" %}
{% block content %}
{% scrollbar args %}
{% endblock %}
with the end result being the scrollbar's template is rendered with the specified args, and its JS and CSS are merged into the compressed_css and compressed_js areas, respectively, above?
I think we get there almost 100% via this approach, without the compressed_js/compressed_css sections, which raises the question of whether then we just included these in all shared pages. (Alternatively, we could use nested/inherited blocks.)
Adam

include static files from django template

I'm trying to include a static html page from a django template.
I tried using {% include the_static.html %} but this doesn't work for some unknown reason.
the_static.html page is a data page that will be modified often with an html editor.
and my_model has a url to this html and include it. But django refuses to find it although I'm sure I've setup the path correctly.
You can write your custom template tag to do this.
Create a file named includestatic.py under appname/templatetags/. Also, remember to create appname/templatetags/__init__.py, to include the app in settings and to restart the server.
includestatic.py should have this code:
from django import template
from django.contrib.staticfiles import finders
from django.utils.html import escape
register = template.Library()
#register.simple_tag
def includestatic(path, encoding='UTF-8'):
file_path = finders.find(path)
with open(file_path, "r", encoding=encoding) as f:
string = f.read()
return escape(string)
To use it in your template, put {% load includestatic %} at the top of your template, and then use the tag like {% includestatic "app/file.txt" %}.
I am not sure I understand everything yet...
You've an HTML page served by Django on a given url, let's suppose it to be http://mydjangodomain/get_the_static/. This URL is set in the urls.py of your model. Ok, that's normal.
You have a django template for this model. Let's suppose it's defined in a template directory mytemplates/mymodeltemplates/ and it's called myfrontpage.html (since in Django templates are html files).
I guess you've an URL defined in your urls.py to server that front page ? Let's suppose it's http://mydjangodomain/get_the_front_page/
Now I don't understand how your front page use your static html. Do your final front page html need the static's URL for a "src" attribute or something like it, or do you need to include the static's html into the front page's html ?
In the 1st case, you already have the URL, it's http://mydjangodomain/get_the_static/ so just use it as if.
In the 2nd case, you don't need the previous URL, get ride of it. Furthermore, put the_static.html in mytemplates/mymodeltemplates/. Then you need the {% include "/mymodeltemplates/the_static.html" %} tag. If this doesn't work, make sure you've the following in your settings:
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
APPLI_ROOT_PATH = "<absolute_path_to_the_application_root_on_your_server>"
TEMPLATE_DIRS = (
'%s/mytemplates' % APPLI_ROOT_PATH,
)
Sort of resurrecting the dead, but at least with django 1.10, there's a very clean answer here:
http://www.effectivedjango.com/tutorial/static.html
an excerpt from that page:
Simple Template Inclusion We want to add the Boostrap CSS to all of
our templates, but we’d like to avoid repeating ourself: if we add it
to each template individually, when we want to make changes (for
example, to add another stylesheet) we have to make them to all the
files. To solve this, we’ll create a base template that the others
will inherit from.
Let’s create base.html in the templates directory of our contacts app.
{% load staticfiles %}
<html>
<head>
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}"
rel="stylesheet" media="screen">
</head>
<body>
{% block content %}
{% endblock %}
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
</body>
</html>
base.html defines the common structure for our pages, and includes a
block tag, which other templates can fill in.
We’ll update contact_list.html to extend from base.html and fill in
the content block.
{% extends "base.html" %}
{% block content %}
<h1>Contacts</h1>
<ul>
{% for contact in object_list %}
<li class="contact">{{ contact }}</li>
{% endfor %}
</ul>
add contact
{% endblock %}
Having followed this exactly, I now have a base.html that includes all my style references and the navigation bars/etc, so the html in the block content is merely the central contents of each (varying) page.
Do you mean that you want to EXTENDS the parent template the_static.html?
If yes, you should add below code at the first line of your children template:
{% extends "the_static.html" %}
Details documentation can be found here

How can I use my site's base template for the Django admin area?

I know that I can override the admin template by creating a template called admin/base.html and writing something like:
<h1>Hello!</h1>
{% block content %}
{% endblock %}
However, my site has its own base template (using "content" for the content block) and I wish to use this for the admin site. In addition to the site's base HTML, I need to add the admin CSS and scripts, such as:
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}" />
So I would override the admin template with a template which inherits from my site's base template. However, if I define a content block in this template to insert content, it is immediately overrided by the individual admin view templates. Changing the block name seems like the wrong solution, as the fact that it is used for the admin templates suggests that it is the correct convention used in Django.
The good practice is to copy the original admin/base_site.html and make adjustments here (editing the title, the branding, adding {% block extrahead %} or {% block extrastyle %} with your own css/js etc.
The admin site is not expected to be integrated inside a custom template, but you can easily accords the style with your own preferences.
Just create an admin/base.html file, and put this inside :
{% extends "base.html" %}
# according base.html to the name of your base layout file

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
});