Django: Extends or Include? - django

My friend and I are having a small argument. In my current Django Project, I have created a file called menu.html which will contain a bunch of links configured and formatted into a list. Instead of manually hard-coding the menu into each page, I am currently including the menu using the following Django/Python code:
{% include 'menu.html' %}
However, my friend is suggesting that this is the incorrect way to do it. He said I need to use extends instead of include and then define content, something like this:
{% extend 'menu.html' %}
{% block content %}
The rest of my content here.
{% endblock %}
That's a bit of extra code. Does it really matter which I use? I would prefer to use the former.

Yes, it matters. First of all extends can only occur as the very first line of the file. Secondly, include pushes and pops a context object on the resolve stack, which means that value created in the context while in the include will go out of scope when it returns.
My rule is: create base.html template files that define the overall structure of your site and use liberal amounts of {% block foo %} around critical areas. Then all of your other templates extends the base (or something that itself extends the base) and you replace those blocks as needed.
include, on the other hand, is good for encapsulating things you may need to use in more than one place, maybe even on the same page.
Update:
I have been using my own library of template_tags for so long that I forget that Django's template language still has major gaps in functionality. The tag in question here is from an early django snippet called expr which I have heavily edited and extended. You can say, for example, {% expr 'Fred' as name %} (or any valid Python expression), and it will store the result in the 'name' slot in the current Context. If this occurs in an included template, name's value will be popped on exit from the template file.
You can sort of achieve this with the {% with %} tag, but expr gives me much greater flexibility, including doing arbitrarily complex calls. This originally came up when having to create complex cached objects that required expensive DBMS interactions that couldn't be done up in the view, they had to be invoked in the template itself.
Email me (in my profile) if you need to get deeper into this.

( his friend )
What I actually meant was defining a base.html so you can inherit a base template consistent of several generic sections, this one includes the doctype, html element defines 3 blocks for content and nav and optional area to override/insert script/link elements in the head.
<!doctype>
<html>
<head>
{%block extrahead %} {%endblock %}
</head>
{%block nav %}
<nav>
<ul>
<li>home</li>
</ul>
</nav>
<div id="content">
{% endblock %}
{%block content %}
{% endblock %}
</div>
</html>
Then you can define homepage.html:
{% extends "base.html" %}
{% block content %}
homepage content
{% endblock %}
homepage.html would then have the navigation because it extends base.html.

In this case placing the menu in base.html and extending from this seems to be more senseful.
including is great for splitting complex template and reusing those chunks.
let's say, you use the same list-style in different places of the site, but you send other queryset to it. as long, as you call the querysets the same, you only need to write the template code once.
Here I use differnt templates for normal- and ajax-requests. But using include let me re-use most parts in both templates

Related

Django nested templates

In trying to keep with DRY, I'm setting up my Django project HTML files now. I have successfully extracted most repeated information to my base.html page. On most (but not all) of my pages, my content is displayed within a general 'panel' which is basically just a container set-up with styling, but it's got a few div-tags to it so it looks a bit ugly and I'm having to type out the exact same code out several times on each page.
My idea was to extract this to a 'panel.html' then call it whenever I need it, for example some pages might just have one 'panel' whereas my dashboard (it's an administrative site) will have maybe 15+. So it seemed a better idea and cleaner to not have to type out all this code each time I need to set up a 'panel'.
My ideal page would look something like..
{% extends 'base.html' %}
{% block content %}
{% extends 'panel.html' %}
{% block panel_content %}
Panel content...
{% endblock panel_content %}
{% extends 'panel.html' %}
{% block panel_content %}
Second panel content
{% endblock panel_content %}
{% endblock content %}
I know I can't use extends multiple times but I'm using it just as an example for what it is I'm trying to achieve.
I am going to potentially have hundreds of these identical 'panels' across my site but each containing different content and it would be so much cleaner if I could just have one stored somewhere in a HTML file and call it however many times I need.
Is there a way to do this?
You can use include
{% include "panel.html" %}
I should mention that too many include statements create a performance issue.

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

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

Indeterminite number of apps/widgets in Django template

I'm working on a site that will have a bunch of pages with an indeterminate amount of "apps" on each page. Something like a calendar app, and a random picture app, or whatever, each in a neat little box. While it's possible to write a template with a bunch of if tags that include other templates, this is a bit of a hassle. I'd like to pass in some variables and have forms on some of these apps, so it would get out of hand quickly. Writing custom inclusion tags will be better than {% include x %}, but it would still be a lot of if statements and writing out every possible app for each page.
Is there any way to loop over something like inclusion tags and include only those that are relevant? Any other completely different solution that I'm missing?
What I'm trying to avoid, whether I use {% include %} or inclusion tags, is this:
{% if apps.calendar %}
{% include "calendar.html" %}
{% endif %}
{% if apps.pictures %}
{% include "pictures.html" %}
{% endif %}
This would mean we'd have to update templates any time a new app was added. What would be nice is something like:
{% for app in apps %}
{% call appropriate include or inclusion tag %}
{% endfor %}
With very few exceptions we use our custom tags all over the place, so we deal with this by simply placing the following in the app/__init__.py file.
from django import template
template.add_to_builtins('content.templatetags.local_tags')
template.add_to_builtins('utils.cachetemplate')
So all of the pages have them available by default. Doesn't seem to impact performance and we use tag names that are unlikely to interfere with other stuff we might include. It's lazy but it works.
Update: OK, I think I better understand what you want. One way of doing this (although I don't really recommend it) is to put the check for the variables inside the included templates. This means you will always have the overhead of including the template, but it will make your other pages marginally less cluttered.
So instead of this in your main file:
{% if apps.calendar %}
{% include "calendar.html" %}
{% endif %}
you simply have:
{% include "calendar.html" %}
and in "calendar.html" you have:
{% if apps.calendar %}
whatever you do for your calendar app
{% endif %}
Update 2:
The last bit of code you show could be done as follows. This takes advantage of the the fact that {% include arg %} "resolves" its argument. This means it can be a variable or a method reference that returns a usable string value that is a template name.
{% for app in apps %}
{% include app %} <!-- or perhaps {% include app.template %} -->
{% endfor %}
Note: Django's template code does not handle top level callables correctly. This means your context cannot pass a reference to a function and expect it to be called and it's output inserted when referenced in a template. Ie. in the example above your list of apps may not be simple functions which you wish to be called. To work as expected a function reference must be either a member of a list or dict, or it must be a method of an object that is passed. We MonkeyPatched this problem long ago because we use curried functions in cached template fragments to defer some heavy DB work. This ticket has been open for over 2 years.

Can we append to a {% block %} rather than overwrite?

In my core.html I have a block labeled javascript. It would be great if I can append more lines to this block without overwriting everything in it.
{% block javascript %}
{{ block.super }}
... more content ...
{% endblock %}
See: Django documentation - Template inheritance
Using block.super works fine when extending a template but not as well when including one, ie:
{% extends "base.html" %} vs. {% include "partial.html" %}
Say you want to include a template in the middle of your page and you'd also like it to add some javascript in a block at the end of the page: calling block.super in the included template will crash.
Cf. Django issues #7324, #12008, #13399 and the related update to the documentation. Cf. include tag note:
The include tag should be considered as an implementation of “render this subtemplate and include the HTML”, not as “parse this subtemplate and include its contents as if it were part of the parent”. This means that there is no shared state between included templates – each include is a completely independent rendering process.
Blocks are evaluated before they are included. This means that a template that includes blocks from another will contain blocks that have already been evaluated and rendered - not blocks that can be overridden by, for example, an extending template.
In that case I'd recommend using django-sekizai, wich allow you to do things like:
{% load sekizai_tags %}
⎧ <p>Some content</p>
<p>Some content</p> | {% addtoblock "js" %}
| <script type="text/javascript">
{% include "partial.html" %} -> ⎨ alert("Hello django-sekizai");
| </script>
<p>Some more content</p> ⎩ {% endaddtoblock %}
{% render_block "js" %}
From django-sekizai README:
The main reason I started this project was the lack of a good media (css/js) framework in django and the django-cms. Yes there is the Media class used in forms in django, but really that doesn't work that well. Usually the frontend guys want to decide on css and javascript files to be included and they don't want to have to edit Python files to change that neither did I want them to change my Python files. Therefor there was a need to allow you to edit contents of templates which are before or after the point where you are now. Also I wanted duplicates to be removed. As a result I wrote django-sekizai, which does exactly that. It's similar to blocks, just instead of inheriting them, you extend them.