I would like to provide the same content inside 2 different base files.
So I'm trying to do this:
page1.html:
{% extends "base1.html" %}
{% include "commondata.html" %}
page2.html:
{% extends "base2.html" %}
{% include "commondata.html" %}
The problem is that I can't seem to use both extends and include. Is there some way to do that? And if not, how can I accomplish the above?
commondata.html overrides a block that is specified in both base1.html and base2.html
The purpose of this is to provide the same page in both pdf and html format, where the formatting is slightly different. The above question though simplifies what I'm trying to do so if I can get an answer to that it will solve my problem.
When you use the extends template tag, you're saying that the current template extends another -- that it is a child template, dependent on a parent template. Django will look at your child template and use its content to populate the parent.
Everything that you want to use in a child template should be within blocks, which Django uses to populate the parent. If you want use an include statement in that child template, you have to put it within a block, for Django to make sense of it. Otherwise it just doesn't make sense and Django doesn't know what to do with it.
The Django documentation has a few really good examples of using blocks to replace blocks in the parent template.
https://docs.djangoproject.com/en/dev/ref/templates/language/#template-inheritance
From Django docs:
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.
So Django doesn't grab any blocks from your commondata.html and it doesn't know what to do with rendered html outside blocks.
This should do the trick for you: put include tag inside of a block section.
page1.html:
{% extends "base1.html" %}
{% block foo %}
{% include "commondata.html" %}
{% endblock %}
page2.html:
{% extends "base2.html" %}
{% block bar %}
{% include "commondata.html" %}
{% endblock %}
More info about why it wasn't working for me in case it helps future people:
The reason why it wasn't working is that {% include %} in django doesn't like special characters like fancy apostrophe. The template data I was trying to include was pasted from word. I had to manually remove all of these special characters and then it included successfully.
You can't pull in blocks from an included file into a child template to override the parent template's blocks. However, you can specify a parent in a variable and have the base template specified in the context.
From the documentation:
{% extends variable %} uses the value of variable. If the variable evaluates to a string, Django will use that string as the name of the parent template. If the variable evaluates to a Template object, Django will use that object as the parent template.
Instead of separate "page1.html" and "page2.html", put {% extends base_template %} at the top of "commondata.html". And then in your view, define base_template to be either "base1.html" or "base2.html".
Added for reference to future people who find this via google: You might want to look at the {% overextend %} tag provided by the mezzanine library for cases like this.
Edit 10th Dec 2015: As pointed out in the comments, ssi is deprecated since version 1.8. According to the documentation:
This tag has been deprecated and will be removed in Django 1.10. Use the include tag instead.
In my opinion, the right (best) answer to this question is the one from podshumok, as it explains why the behaviour of include when used along with inheritance.
However, I was somewhat surprised that nobody mentioned the ssi tag provided by the Django templating system, which is specifically designed for inline including an external piece of text. Here, inline means the external text will not be interpreted, parsed or interpolated, but simply "copied" inside the calling template.
Please, refer to the documentation for further details (be sure to check your appropriate version of Django in the selector at the lower right part of the page).
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#ssi
From the documentation:
ssi
Outputs the contents of a given file into the page.
Like a simple include tag, {% ssi %} includes the contents of another file
– which must be specified using an absolute path – in the current page
Beware also of the security implications of this technique and also of the required ALLOWED_INCLUDE_ROOTS define, which must be added to your settings files.
Related
I would like to share a template between AJAX and regualr HTTP calls, the only difference is that one template needs to be served with the base.html html, the other one without.
Any idea?
The other answers require you to pass an additional context variable. But as long as you can access the request object, there is no need:
{% extends request.is_ajax|yesno:"app/base_ajax.html,app/base.html" %}
I found this to be much more convenient.
Use a variable.
{% extends base_template %}
and in your view, set it to "base.html" in your view, or a new "ajax.html" file which just provides the block and nothing else.
{% extends override_base|default:'base.html' %}
P.s. I know this is an old question, but I found it when searching for an answer. Maybe it'll help someone else with the same problem.
You can use {% extends variable %}
Pass a variable base template name in when you create the context in the view.
http://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#extends
I'm new to Django but I've been really enjoying it. But occasionally I seem to run into places where I just don't seem to get things correct. So, I'm asking for some help and guidance.
I'm trying to extend the object-tools for one of my models so I can have a Print button next to History.
My templates is as follows:
project/app/templates/admin/
I'm successfully extending base_site.html with no issues.
project/app/templates/admin/base_site.html
However, when I add change_form.html like so:
project/app/templates/admin/change_form.html
With the following:
{% extends 'admin/change_form.html' %}
{% block object-tools %}
One
Two
{% endblock %}
I get an exception: maximum recursion depth exceeded while calling a Python object
This seems like I'm missing something quite basic.
Things that I've tried:
Many variations of the {% block %}
extending base_site, base etc ...
adding /model as part of the path (project/app/templates/admin/model/change_form.html)
I'm confused and unsuccessful.
P.S.: I'm also using a bootstrap theme from here http://riccardo.forina.me/bootstrap-your-django-admin-in-3-minutes/ but for the purposes of this problem I'm currently not using it.
The problem is that admin/change_form.html in your {% extend %} block is getting resolved as project/app/templates/admin/change_form.html.
One solution is to create a subdirectory of templates named for your app - possibly project/templates/admin/app/change_form.html.
In order to override one or more of them, first create an admin directory in your project’s templates directory. This can be any of the directories you specified in TEMPLATE_DIRS.
Within this admin directory, create sub-directories named after your app.
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing-an-admin-template
That's because you're extending the template with itself. What I do is put my custom admin templates in templates/admin. Then in that same folder I symlink to the django admin folder (templates/admin/admin).
So my extends looks like:
{% extends 'admin/admin/change_form.html' %}
Make sure you also override index.html if you want to go down that path.
The best way to do this that I have found is to use '..' to go up a couple of directories, then go back down into directories that should only be found in the Django code base.
As the Django templates are in something like "django/contrib/admin/templates/admin", I found that this worked me:
{% extends "../../admin/templates/admin/change_form.html" %}
If that still causes a clash with some other structure you have, you could go further:
{% extends "../../../contrib/admin/templates/admin/change_form.html" %}
or even:
{% extends "../../../../django/contrib/admin/templates/admin/change_form.html" %}
Although it is a little hacky, at least by doing the above you don't have to use some other technique that involves copying the django source or setting up a symlink.
What I'd like to do (for a recent changes 'widget' - not a django widget in this case) is pass a urlname into my template as a variable, then use it like so: {% url sitechangeobject.urlname %} Where urlname is a string containing a valid name for a url.
Is this possible? The template keeps breaking saying it can't find sitechangeobject.urlname as a name (which is quite right, it doesn't exist). Is there any way to make it look inside that variable?
There are other ways to solve this problem if not, just thought I'd check though.
Thanks!
As of Django 1.3 the {% url %} tag properly supports:
{% url view_name_variable %}
{% url 'view_name_string' %}
...this becomes the default behaviour in Django 1.5.
Previously, you had only the option to do this:
{% url view_name_string %}
To get the tag to work in this way in Django 1.3 and 1.4 projects, you will need the following line to the top of every template you use it in:
{% load url from future %}
According to the Django 1.3 release notes:
...in Django 1.5, the old behavior will be replaced with the new behavior. To ensure compatibility with future versions of Django, existing templates should be modified to use the new future libraries and syntax.
Note that support for {% load url from future %} has been removed in Django 1.9.
Note: this answer is only really relevant to versions of django before 1.3. If you are using django 1.3 or later, the required functionality is built-in - please see meshy's answer.
The built-in url tag cannot do this. However django-reversetag does exactly this (and more).
According to the readme, the reverse tag provided by this code provides:
Consistent syntax ("string literals" and variables)
Ability to reverse view names stored in context variables
Partial reversing
for django 1.5
may be this is useful
usually, to access a variable passed from view
we use
{{variable}}
however, for url in template, the following does not work:
{% url 'app:namespace' {{varible}} %}
simply use the following is fine:
{% url 'app:namespace' varible %}
if you are using Django 1.5 and up, django-reversetags is not required anymore for just passing view names as variables into templates, to be used within the url tag.
I was confused with the availability of django-reversetags, just thought of updating the matter correctly here.
In template ---->
{% url 'app_name:urlName' arg1=value arg2=value %}
In app url ---->
url(r'^goto/(?P<arg1>[0-9A-Za-z_\-]+)/(?P<arg2>[0-9A-Za-z]{1,13}])/', ViewName, name='urlName'),
In project Url---->
path('v1/to_app/', include(('app_name.urls','app_name'),namespace="app_name")),
This will help...!
How can I write a tag "copyblock" for Django templates?
For such a function:
<title> {% block title %} some title... {% endblock %} </title>
<h1>{% copyblock title %}</h1>
Take a look at the solutions mentioned in this question:
How to repeat a "block" in a django template
Django's template parser doesn't expose blocks by name. Instead, they are organized into a tree structure in the Django Template's nodelist, with rendering pushing and popping on the stack of template nodes. You'll have a nearly impossible time accessing them in the way your example indicates.
The SO link that ars references provides suggestions on the best solutions. Of those solutions, defining a variable in the context (ie: {{ title }} in the spirit of your example) that can be reused is probably the most straightforward and maintainable approach. If the piece you want to duplicate goes beyond a simple variable, a custom template tag is probably the most appealing option.
I'm having an issue with django templates at the moment. I have 3 template files basically:
Base
story_list
story_detail
Story_list and _detail extend Base, and that works perfectly fine. However, list and detail share some code that extend the base template for my sidebar. I'm basically repeating a chunk of code in both templates, and the programmer in me says that's just wrong. There has to be a better way, I'm sure of it. I've tried includes, however I have in the included file:
{% block item %}
content stuff
{% endblock %}
for about 3 blocks. The problem is that none of that is being picked up/rendered. If I include the file in a block section that extends base, then it dumps everything properly, but if I don't include it in a block, I get nothing. Is SSI the way to go? I toyed with that, but that didn't seem to work properly either. Any help is appreciated.
Generally, using includes is not the answer with Django templates. Let me answer your question on several fronts.
First, let me address the sidebar.
Are nearly all the common pages going to be using that sidebar? Put it in Base. Don't override those sidebar blocks (i.e. don't write them at all in your Story_* templates).
Is this sidebar unique to the Story_* templates? Make another template called, say, Story_base and extend that. This is akin to making an abstract superclass in Java. (Answer was in my head, but wording was mercilessly ripped off from jpwatts.)
Next, let me address template inheritance. Say you have a template named Story_list that extends Base. At this point, after just putting {% extends "Base" %}, Story_list is exactly Base. Anything else you put in Story_list is ignored, because the template is already complete. The only thing you can do now is override blocks that have been defined in Base.
Finally, let me address includes. Try to always avoid them. Other templating engines, such as PHP, seem to encourage using includes. However, this can lead to less manageable templates in the long run. It's slightly harder to glance at an included snippet and immediately ascertain its place in your template hierarchy. They're also harder to refactor into the template hierarchy, especially if you include them at several levels (once in Base, twice in Story_base, once in some of the Story_*, etc.).
If there is common code between the story templates that isn't needed site-wide, I'd create a story_base (extending the original base) and have my story templates extend that.
You have an {% include %} tag for this.
{% include xxx.html %}
This tag works.
An alternative way is to use filter. Filter calls a function for rendering, template can be used while rendering.