Django template nested include passing variables - django

I use django template index.html to render the frontpage. It includes another template to create a link icon. This template url_icon.html includes another template icon.html. When passing the arguments down the way, I face with an error. How to fix it?
index.html
.
.
.
{% include "url_icon.html" with name="return" url="/" %}
.
.
.
url_icon.html
{% include "icon.html" with icon={{ name }} %}
icon.html
<img src="/static/images/{{ name }}.png" />
Causing an error:
Could not parse the remainder: '{{' from '{{'

it looks like there are a few things you can do to improve/fix this. Addressing #1 and #2 should fix your issue. I've also added suggestions for best practices that would probably require refactoring (#3, #4).
It looks like you need to remove the curly-braces from name inside the {% include %} tag. Context variables can be used inside tags without extra syntax.
url_icon.html:
{% include "icon.html" with icon=name %}
icon.html will have access to name since you're not using the only keyword when updating its context, so your code might appear to work at first ({% include %} documentation). However, it looks like your intention is to refer to it as icon.
Use the variable icon in instead of name
icon.html:
<img src="/static/images/{{ icon }}.png" />
Optional suggestion: Use Django's staticfiles system
Try using the {% static %} tag for your icon. This will help make deployment easier, especially if you use a separate CDN from your webserver. There's lots of literature on how to set up staticfiles for Django projects in production, it's a large topic, but you'll be able to approach it more easily if you use the {% static %} tag from the beginning.
Optional suggestion: Django's URL routing system
Your route in index.html is hard-coded to be "/". Django has a powerful URL referencing system to leverage. If you've defined the root URL / using Django too, you can refer to it by name. Docs: {% url %}, and for the back-end, reverse().

Related

django url NoReverseMatch works in 3rd party app but not my project

I am integrating django-zinnia 0.12.3 into my django 1.4 project. I have it installed and working. I want to override its zinnia/base.html template so that all the content appears using my site's template. The zinnia templates extend 'zinnia/base.html'.
When I copy the file zinnia/templates/zinnia/base.html to myproject/templates/zinnia/base.html all the zinnia {% url %} stopped working and gave NoReverseMatch. Even if I made zero changes to the file. For example:
{% url 'zinnia_entry_archive_index' %} --> returns:
NoReverseMatch Reverse for ''zinnia_entry_archive_index'' ... not found
{% url 'admin:app_list' 'zinnia' %}" title="{% trans "Dashboard" %} --> returns:
NoReverseMatch u"'admin" is not a registered namespace
I was solved the problem by removing the quotes around the url names, for example:
{% url zinnia_entry_archive_index %}
However, if I remove the copy of base.html that I put in myproject/templates/zinnia (in other words it uses the original one in the zinnia project), the urls work again.
My question is why does it work with the quotes inside the original zinnia folder, but not from within my project folder?
The reason is that in Django <= 3 the url tag takes url name without quotes. But in Django 1.4+ it is deprecated and url name without quotes is gone in Django 1.5:
So if you are using Django <= 1.4 do not remove the quotes (unless you are passing context variable) around url names. Instead do this for compatibility reason if you ever wanted to upgrade your django version:
{% load url from future %}
{% url 'zinnia_entry_archive_index' %}
Documentation
Don’t forget to put quotes around the function path or pattern name!
Changed in Django 1.5: The first parameter used not to be quoted, which was inconsistent > with other template tags. Since Django 1.5, it is evaluated according to the usual rules: > it can be a quoted string or a variable that will be looked up in the context.

Why does using a variable in settings.ALLOWED_INCLUDE_ROOTS won't let me use {% ssi %}?

Problem
I'm using Django 1.3. I will have to use many different JavaScript functions (like 10 or something) in my template.
What I first did was to put them in the <script> tag, which worked fine. But now that it works, I want to separate them from the template code. It would make the code way more read'able.
So I thought of using the {% ssi "..." parsed %} thing. Since I use Django template tags in my JavaScript code, I can't just link them from my static files with <script src="..."></script>.
Here is what works :
# This will allow the {% ssi %} tag to include files from the given paths
ALLOWED_INCLUDE_ROOTS = (
'/THIS/IS/THE/FULL/PATH/TO/MY/PROJECT/static/js/',
)
Here is what does not work :
# Project root for further paths
PROJECT_PATH = os.path.dirname(__file__)
# This will allow the {% ssi %} tag to include files from the given paths
ALLOWED_INCLUDE_ROOTS = (
PROJECT_PATH+'/static/js/',
)
I double-checked that the two strings were the same (with ./manage shell) and they are exactly the same (with trailing / and all).
Questions
Why does the second code renders me [Didn't have permission to include file] in my template ?
Also, how should I link the file to include in the {% ssi %} tag ? Since {% get_static_prefix %} does not work, I'm currently using the file's full path, which is ugly.
As odd as it may appear, I didn't make any change in my settings.py but it is now functionnal. I believe Mike Cooper was right and some remote code was breaking ALLOWED_INCLUDE_ROOTS path.
ALLOWED_INCLUDE_ROOTS is likely a constant due to it's naming convention. Constants aren't meant to be variable.
http://en.wikipedia.org/wiki/Constant_(programming)#Naming_conventions

What is "load url from future" in Django

When I read django code sometimes, I see in some templates "load url from future". I am not quite sure what this is but I do know it has something to do with URLs. How and when is this load url from future supposed to be used?
It's due to a change to the url tag enacted in 1.3:
Changes to url and ssi
Most template tags will allow you to pass in either constants or variables as arguments – for example:
{% extends "base.html" %}
allows you to specify a base template as a constant, but if you have a context variable templ that contains the value base.html:
{% extends templ %}
is also legal.
However, due to an accident of history, the url and ssi are different. These tags use the second, quoteless syntax, but interpret the argument as a constant. This means it isn’t possible to use a context variable as the target of a url and ssi tag.
Django 1.3 marks the start of the process to correct this historical accident. Django 1.3 adds a new template library – future – that provides alternate implementations of the url and ssi template tags. This future library implement behavior that makes the handling of the first argument consistent with the handling of all other variables. So, an existing template that contains:
{% url sample %}
should be replaced with:
{% load url from future %}
{% url 'sample' %}
The tags implementing the old behavior have been deprecated, and 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.
I will put this in a separate answer due to the following salient Exception in connection with templates:
If you get a django.core.urlresolvers.NoReverseMatch Exception thrown from within a django template (Django version >1.4) parser, it may just be the usage of {% load url from future %} within the template.
In this case, simply quote the url that is passed to the url-tag. That is {% url someurl %} should become {% url 'someurl' %}. Thanks to Ignacio VA for pointing me in that direction.

How can two apps respond to the same URL in Django?

I think I'm missing a basic concept here. In the stereotypical Django project, you'd have two apps responding to different urls:
http://localhost/myproj/app1/33
http://localhost/myproj/app2/newcomment.html
But what mechanisms exist to handle cases where the two apps are complementary - say one provides content, and the other provides presentation? Or maybe one is content and the other is a kind of static, side-wide content that should appear on every page.
In particular, I don't understand how both apps can use template inheritance to extend the same template. Imagine there's a base app "baseapp" with a template "base.html":
...
<div blah blah>
{% block content %}
{% endblock %}
...
App1 extends it:
{% extends "baseapp/templates/base.html" %}
{% block content %}
... here's the actual content...
{% endblock %}
App2 adds a little banner or something:
{% extends "baseapp/templates/base.html" %}
{% block content %}
<div class="banner">Please support our site!</div>
{{ block.super }}
{% endblock %}
So what are the ways that both templates can get displayed? I can think of:
app1 could extend app2's templates. But this seems wrong: app1 is the content provider, and shouldn't be dependent on something as trivial as app2.
app2 could extend app1's templates. But this seems wrong: now the URL scheme would have to funnel every URL through app2 (if I understand correctly)
middleware?
As I said, I'm probably missing something very basic. Or I'm making some very faulty assumptions that I don't know about. (This question is my third attempt, after Embed an optional Django application in another page, if that app is present and How to capture and display information external to my webapp, but relevant to users of it? - I'm having trouble framing the issue.)
App doesn't respond to an URL, a view does. View is a function that can use models, forms and other object from any app. There isn't any problem here.
If you want to add something to template, inheritance isn't the only way. You'd better use custom context processor or custom template tag.
I think what I was actually missing here:
Apps can override templates just by including a template of the right name in the right subdirectory. The Django docs don't make this very clear, that I can see: they refer to this functionality in the context of Admin templates
When overriding a template as above, you can't extend it, but:
This snippet lets you both override a template and extend it: http://djangosnippets.org/snippets/1376/
Here's a closely related question: Django: Overriding AND extending an app template

Difficulty overriding Django Admin template

I'm using Django 1.2.4 on Ubuntu 10.10. I'm trying to override the index.html template for the admin module. I've been following these instructions. I also looked at this question, but I'm still having difficulty.
The instructions say to create an admin directory in the templates directory:
templates/
admin/
index.html
I want to override a single block in the index.html. (Really, all I want to do is append some text to the end. Is there an easier way than copy/pasting the entire block and changing it?) (Update: Looks like {{block.super}} may help.)
To signal that I'm overriding, I put this at the top of my index.html:
{% extends "admin/index.html" %}
Of course, that results in a stack overflow (from the terminal):
Exception RuntimeError: 'maximum recursion depth exceeded in __subclasscheck__' in <type 'exceptions.RuntimeError'> ignored
What is the correct way to do this? I tried a symlink per an answer on the linked question, but that resulted in the following:
me#mycomp:~/foo$ sudo ln -s /usr/local/lib/python2.6/dist-packages/django/contrib/admin/templates/ django_admin
[sudo] password for me:
ln: creating symbolic link `django_admin': Protocol error
What am I doing wrong?
The recursion error is because you're extending the admin/index.html with itself.
You can either:
copy the entire admin/index.html template in your templates/admin/ directory, and it will replace the default template with yours
override the index.html per app or model, as explained here
I know this is late after the question, but you know, google traveling...
Amend settings.py with an extra template folder, for example:
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
"/home/mysite/webapps/django/myproject/templates",
"/home/mysite/webapps/django/lib/python2.7/django/", # extra folder
)
Then in myproject/templates/admin add your own index.html like:
{% extends "contrib/admin/templates/admin/index.html" %}
{% block branding %}
<h1 id="site-name">Administration for TheLittleButtonCo</h1>
{% endblock %}
Variations are possible, obviously. This works on Django 1.3.1 final
Not sure if you found the answer, but you need to change
{% extends "admin/index.html" %}
to
{% extends "admin/base_site.html" %}
as that is what the original index.html page overwrites. Because the Django system searches your templates folder before using the default admin one, so in this case it finds the admin/index.html in your templates, then it's trying to extend itself with the extend (hence the recursion error).
For reference you can customise the base_site.html in you templates too, it extends base.html. The best thing to do is copy the original from:
/usr/local/lib/python2.6/dist-packages/django/contrib/admin/templates/
and paste it into your templates folder as a starting point
I use an extra package, called django-smart-extends