Django static file inheritance - django

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 %}

Related

How to create reusable components for UI in Django

I am building a project in Django which has 5 different applications inside it. Some applications are falling under same pattern and some are not. Can I create a UI components using bootstrap on the top of all these applications to reuse over the entire project. Any help would be appreciated.. Thanks in advance
Usually that is done by creating a base template and making other templates inherit from it like this:
base.html
<html>
<head>
<title>Title</title>
</head>
<body>
<navbar> # example navbar that will be visible in each template that will extend this one
<ul>
Home
Contact
Something else
</ul>
</navbar>
{% block content %} # here is where the content of child templates will be seated
{% endblock %}
</body>
</html>
then you will make any other template and extend it with base.html
your_other_template.html
{% extends 'base.html' %} # this line makes sure your child templates inherit the html of your main template
{% block content %} # here is where you will place the content of your other templates
<h1> This is the content of a child template </h1>
{% endblock %}
Paste your component in an empty html file and then use an include statement to load that file into you template html.
https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#include
This way you can insert you components more dynamically throughout your project.

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

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

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 templates, including page(s) that injects code into parent block

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.

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.