Django Custom Inclusion Tags - django

I'm trying to build my own template tags.
I have no idea why I getting these errors. I'm following the Django doc's.
This is my app's file structure:
pollquiz/
__init__.py
show_pollquiz.html
showpollquiz.py
This is showpollquiz.py:
from django import template
from pollquiz.models import PollQuiz, Choice
register = template.Library()
#register.inclusion_tag('show_pollquiz.html')
def show_poll():
poll = Choice.objects.all()
return { 'poll' : poll }
html file:
<ul>
{% for poll in poll
<li>{{ poll.pollquiz }}</li>
{% endfor
</ul>
in my base.html file im am including like this
{% load showpollquiz %}
and
{% poll_quiz %}
Bu then I get the the error:
Exception Value: Caught an exception while rendering: show_pollquiz.html
I have no idea why this happens. Any ideas? Please keep in mind I'm still new at Django

Shouldn't all custom filters be inside the templatetags directory?
templatetags/
__init__.py
showpollquiz.py
then
#register.inclusion_tag('show_pollquiz.html')
looks in MY_TEMPLATE_DIR/show_pollquiz.html for the template

You forgot to close your template tags... Also, you should change the name in the for tag, you can't have for poll in poll:
<ul>
{% for p in poll %} <!--here-->
<li>{{ p.pollquiz }}</li>
{% endfor %} <!--and here-->
</ul>
Also notice you're not using the inclusion tag you defined at all. I think you got some code mixed up, try to go over a tutorial start to end and things will be clearer.

I'd not bother with writing your own template tags: take things one step at a time and stick to the basics for now. There's nothing wrong with {% include 'show_pollquiz.html' %}

I found the problem. The problem was that the #register.inclusion_tag('show_pollquiz.html')
inclusion tag is obviously looking for the template in the default_template directory. So that is why i got the error.
According to me this is not clear in the documentation. But I guess its how it is, being a template and all...
Oh , well.
Now, how would I put the #register.inclusion_tag('show_pollquiz.html') to look in the same folder as the app? under templatetags/?

Related

VSCode breaks Django template tags with newline

Problem:
{% extends 'base.html' %} {% block title %} Dashboard {% endblock %} {% block pagetitle %}
becomes
{% extends 'base.html' %} {% block title %} Dashboard {% endblock %} {% block
pagetitle %}
Note that the {% tag %} is being broken with a new line. This causes syntax errors with django templates.
I've tried most top django template extensions and this does not fix the issue.
I've also tried these settings:
"[html]": {
"editor.formatOnSave": false,
},
"html.format.wrapLineLength": 0,
"html.format.enable": false,
"prettier.disableLanguages": ["html"]
Desired Behavior:
Automatically format *.html files, while preserving django template tags, not breaking them up with newlines.
Sub-optimal (but acceptable) behavior: don't format *.html files at all.
I had the same issue and the only way I found that solved it is to disable the default HTML formatter. Unfortunately, I did not find a way to make it format Django template tags correctly. You can do the same if you go to VS Code Preferences > Settings > User > Extensions > HTML and uncheck 'Enable/disable default HTML formatter'.
I solved this by following this advice: https://stackoverflow.com/a/73892745/1257347
TLDR: install the djLint extension (and remember to do $ pip install djlint)
I got it to work by simply adding {{""}} between the {% tag %} that were being broken.
Example:
{% extends 'main/base.html' %} {% block title_block %}Homepage{% endblock%}
{{""}} {%block style_ref_block%}{%endblock%} {{""}} {% block body_block %}
This Didn't work for me.
The hack I found was to set the vscode language to jinja instead of the auto detected html
reference
I've also just experienced vs-code misbehaving on django template tags (i.e. deleting curly braces).
I don't like the idea of disabling HTML formatting just to support templates (i.e. vs-code Preferences/Settings/Extensions/HTML: disable (uncheck) "HTML>Format:Enable"). This is arguably a step backwards, but it does stop vs-code misbehaving.
Instead, I chose to install (vs-code Preferences/Extensions) the 'Django' extension, by Baptiste Darthenay. This was a better way to go, because it works, gracefully, preserves native vs-code HTML formatting, and includes a nice set of django snippits, which saves me keystrokes when embedding template code. Tada!
BTW, before finding Baptiste's awesome extension, I also tried keeping vs-code HTML formatting enabled, AND enabling 'HTML>Format:Templating', which promised to "Honor django and other templating language tags"; it did not.

Django Pass Multiple Parameters to Custom Template Filter Inside If Statement

I have an issue. I've written a custom template tag with a function signature like this-
def has_paid_for_article(article, request):
Now, in my template tag I have a conditional statement to determine whether a user can download an article or not (this is determined by if the article is older than two years or the logged in user has paid for the article). Here's the snippet-
{% if article|is_older_than_two_years %}
<span class="amp">& </span>{% get_article_download_link article %}
{% else %}
download
{% endif %}
The aforementioned snippet works fine, however I need to call the has_paid_for_article() function inside of a conditional statement. I've tried the following ways to make this happen-
{% if article|is_older_than_two_years or article|request|has_paid_for_article %}
,
{% if article|is_older_than_two_years or [article, request]|has_paid_for_article %}
This one works outside of the conditional statement-
{% if article|is_older_than_two_years or has_paid_for_article article request %}
What would be the correct syntax here? Also, I've read other posts on the topic, I CANNOT put this logic in the view. I won't go into detail, but with the way it works, that is not an option. Thank you!
Try
{% if article|is_older_than_two_years or article|has_paid_for_article:request %}
See Writing custom template filters

Handlebars.js in Django templates

I need a javascript templating system and i think handlebars.js does an excellent job in this case.
I'm having syntax conflicts with handlebars templates inside a django template because django tries to render handlebars variables.
Is there a tag in django templates to stop rendering a block with curly braces?
Something like:
{{ django_context_varable }} #works
{{% raw %}}
<script id="restaurants-tpl" type="text/x-handlebars-template">
<ul>
{{#restaurants}} #not rendered by django, plain text
<li>{{name}}</li>
{{/restaurants}}
</ul>
</script>
{{% endraw %}}
Edit
Likely i found this. It works fine.
Update
Django 1.5 supports verbatim tag natively.
I use a custom template tag for another js templating system, here:
https://gist.github.com/629508
Use in template:
{% load mytags %}
{% verbatim %}
{{ This won't be touched by {% django's %} template system }}
{% endverbatim %}
Edit: This custom template tag is no longer necessary, as Django's template language now supports the {% verbatim %} template tag.
Is there a tag in django templates to stop rendering a block with curly braces?
OLD Answer for Django 1.0-1.4: No, though you could though you could put the block in a separate file and include it without rendering or use a different templating engine.
New Answer: The answer above was correct in August 2011 when the question was asked and answered. Starting in Django 1.5 (released Feb 2013, though alpha/beta versions in late 2012), they introduced the {% verbatim %} and {% endverbatim %} which will prevent the django template engine from processing the content in the block.
So for the question asked the following will work in django 1.5+ out of the box:
{{ django_context_varable }} #works
{% verbatim %}
<script id="restaurants-tpl" type="text/x-handlebars-template">
<ul>
{{#restaurants}} #not rendered by django, plain text
<li>{{name}}</li>
{{/restaurants}}
</ul>
</script>
{% endverbatim %}
The documentation on verbatim is here. Yes, this was noted by others earlier, but as this is the accepted answer I should list the easiest solution.
I wrote a very small django application : django-templatetag-handlebars exactly for that purpose.
{% load templatetag_handlebars %}
{% tplhandlebars "tpl-infos" %}
{{total}} {% trans "result(s)." %}
<p>{% trans "Min" %}: {{min}}</p>
<p>{% trans "Max" %}: {{max}}</p>
{% endtplhandlebars %}
Render your block as usual using Handlebars.js API :
var properties = {
total: 10,
min: 5,
max: 4
};
var template = Handlebars.compile($('#tpl-infos').html()),
rendered = template(properties);
I wrote it the day #chrisv published its package, with a KISS approach in mind. It is mainly based on Miguel Araujo's gist : https://gist.github.com/893408.
for a deeper integration between handlebars and Django (including optional on-the-fly precompilation) check out my project at
https://bitbucket.org/chrisv/django-handlebars/
It basically works like this:
create HB template under
appdirectory/hbtemplates/myapp/template.html
(just like Django template)
in your app, use
{% handlebars myapp %}
template tag and render template like so:
Handlebars.templates["myapp.template.html"]({context:"value"});
Compile your handlebars first!
From handlebars precompiling documentation:
In addition to reducing the download size, eliminating client-side compilation will significantly speed up boot time, as compilation is the most expensive part of Handlebars.
You can compile templates in your build environment using handlebars npm module, or integrate it with a build tool like gulp with gulp-handlebars.
After compiling, your handlebars templates can be served as static resources and bypass server side rendering altogether. Makes it easier on caching too :)
Typical usage would look like this:
<div id="restaurants-tpl">
Waiting for content...
</div>
<script src="{% static 'js/handlebars.runtime.js' %}"></script>
<script src="{% static 'js/templates.js' %}"></script>
<script>
// Let django render this as a json string
properties = {{ properties }};
// Use Handlebars compiled template imported above
rendered_html = Handlebars.templates["restaurants-tpl"](properties);
// Set element content
document.getElementById("restaurants-tpl").innerHTLM = rendered_html;
</script>
Django's templating system doesn't support escaping blocks at a time. It would be easy to work around were it not for the fact that when templates are processed the tokenizer doesn't keep exact information on what the tokens looked like before they got tokenized.
I have used the following work-around which is ugly, but (sort of) works. Use different tag delimiters in your templates and a django template tag that translates those back to what you actually want:
#register.tag(name="jstemplate")
def do_jstemplate(parser, token):
while self.tokens:
token = self.next_token()
if token.token_type == TOKEN_BLOCK and token.contents == endtag:
return
self.unclosed_block_tag([endtag])
nodelist = parser.parse( ('endjstemplate',) )
parser.delete_first_token()
s = token.split_contents()
tmpl_id = Variable( s[1] ) if (len(s) == 2 and s[1]) else ''
return JsTemplateNode( nodelist, tmpl_id )
class JsTemplateNode(template.Node):
def __init__(self, nodelist, tmpl_id=''):
self.tmpl_id = tmpl_id
self.nodelist = nodelist
def render(self, context):
content = self.nodelist.render(context)
return u'<script id="%s" type="text/x-handlebars-template">%s</script>' % (
self.tmpl_id.resolve(context),
re.sub( ur'{\$(.*?)\$}', u'{{\\1}}', content ), )
For bonus points you can leverage Django's templates within your templates ...
which will probably cook your brain trying to untangle later:
{% jstemplate "restaurants-tpl" %}
{$#restaurants$}
<div id="<$name$<" class="{$type$}">
<ul class="info">
{$#if info/price_range$}<li><em>{{ trans "Price Range" }}:</em> {$info/price_range$}</li>{$/if$}
{$#if info/awards$}<li><em>{{ trans "Awards" }}:</em> {$info/awards$}{$/if$}
</ul>
<div class="options">
<button>{% trans "Reservation" %}</button>
</div>
</div>
{$/restaurants$}
{% jstemplate %}
Actually I wrote a custom template filter which goes like this:
from django import template
register = template.Library()
def handlebars(value):
return '{{%s}}' % value
register.filter('handlebars', handlebars)
and use it in a template like so:
{{"this.is.a.handlebars.variable"|handlebars}}
It's the simplest thing I could think of. You just have to put your handlebars variable name in quotes. I regret I hadn't got this idea before I struggled with ssi. It works also with keywords:
{{"#each items"|handlebars}}
Why not use jinja2 instead? IMO, they're both elegant to use. Here's an excellent article about it: Using Jinja2 with Django

The same data in all django templates

I have created my text based game and my game pages have structure like this:
{% extends 'base.html' %}
{% block content %}
// content
{% include 'links.html' %}
{% endblock %}
Now I'm thinking about notifying players about a new message at the top of every page, so I have to update only base.html to show the information, however, I have to add data about new messages to every template before rendering. Maybe is there a quicker way to do that?
You probably want to look into Context Processors -> docs. That's how you automatically add stuff to your templates. Here's a detailed example -- it's old, but I think it still works.
Or you can just use the messages framework, which has the appropriate Context Processor implemented and should do what you need here.

django extends problem - the child template is not showing

I've already configured the necessary things to work the extends template function in django. here's my codes:
in settings.py
def my_dir():
import os.path
return os.path.abspath(os.path.dirname(__file__))
TEMPLATE_DIRS = ( my_dir() + '/app/templates', ) #dynamic template directory
in base.html - located in app/templates/site
....
<div id="SideBar" class="FloatLeft">
{% block sidebar %} {% endblock %}
</div>
....
in sidebar.html - located in app/templates/site
{% extends "site/base.html" %}
{% block sidebar %}
some code here
{% endblock %}
I've tried also the {% include "site/sidebar.html"%} tag in the base.html to check the template directory, and yes include tag is working...
what's the problem in the {% extends %} ? why does it doesnt detect its parent template..
please help me guys.. your help is greatly appreciated... im still waiting for the answer.. tnx
Which template are you rendering in your view? It should be the child, not the parent.
I am not sure what yout problem is, but you should check the following points :
The {% extends %} tage should be the first one in the template file (and put a blank line afterwards to be sure)
I think that the reference to the base template is relative to you TEMPLATE_DIR. Try different things like putting both templates at the same level etc.
Check all the tags in both templates to be sure that they are all correctly formatted
Check the encoding of the files. If it is UTF-8, try to disable the BOM in both files.
Maybe it is a problem with your directory setting. Try to hard code the absolute path to check that.
These are the problems I can imagine, but I can't guarantee that it will work.
The answer Daniel Roseman gave is spot on, but there is a quick and easy way around this if pointing to your child template is not practical (as it might not be with more complex projects).
In your child template, remove the {% extends "" %} tags you have that are pointing to your parent.
In your parent template, replace {% block content %} with {% include "path/to/child/template" %}
That's it! Your child template will now load into the block content exactly as if you had rendered it directly.
There are a lot of problems. The short answer is "No, you can't change template dirs on-the-fly, and even if you could, you would do it definitely not the way you're doing it now"
Your main issue is that you're forgetting a comma in the TEMPLATE_DIRS setting. Try this:
TEMPLATE_DIRS = ( my_dir() + '/app/templates', )
Please disregard cheshire's answer.
Use os.path.join to combine 2 directories.
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates'),
)
Here I am assuming that templates is a directory where you keep your templates. Now, to access the templates this is the base directory for them. So to extend base.html in some other file do like this -
{% extends "base.html" %}
...
{% endblock %}
Are you sure you have the proper template loaders setup?
You should have this in your settings.py:
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)