Alias Django Template Tag - django

So I often have to use something like the following in my Django templates:
{% include "conname.html" %}
I'd like to be able to instead just have my own tag and only have to type something like
{% conname %}
Is there an easy way to setup some sort of alias so that when ever the template engine sees the conname tag it knows that should actually be a specific include tag?

Pretty simple, in a module just add the following code (mine are usually called custom_tags.py:
from django import template
register = template.Library()
#register.simple_tag
def conname():
return '''{% include "conname.html" %}'''
#to make it available everywhere (i generally add this to my urls.py
from django.template.loader import add_to_builtins
#this will be aded to all templates
add_to_builtins('custom_tags')
In your template you would just use {% conname %}
Or you could make it more complicated and programatically call IncludeNode but that is overkill.

Related

Can't use django variable in include tag

I'm trying to include a .html using
{% include "paintings/experiments/points/{{substance.name}}.html" %}
This however leads to the error TemplateDoesNotExist.
If I hardcode the name of the .html file, it does work.
{% include "paintings/experiments/points/fabric.html" %}
And, in fact, I can use {{substance.name}} inside the included html, were it does indeed get substituted for fabric. Why can I not use a django variable when using an include tag?
I doit with the add templateTag.
{% include "paintings/experiments/points/"|add:substance.name %}
Notice that substance.name should have .html . I'm using this approach to use dynamic Templates. So in a context_processor I set the variable value and use it normally, like this:
{% include ""|add:paginationTemplatePath with page=page_obj %}
In this case, I change the paginationTemplatePath given certain conditions on the context_processor.
I'm exposing this example in order to enrich the answer for other cases, as use include with variable page.
include template tag was designed to accept either string or variable. If you try to use the above, it's just going to be string. But you can manipulate strings with template filters and tags.
You can create custom template tag that creates variable and then use that newly created variable in the include tag. If you check the documentation on Custom template tags and filter you'll see how they work and what are the requirements for them to work.
First you must create a directory inside your app named templatetags
myapp/
__init__.py
models.py
templatetags/
__init__.py
custom_tags.py
views.py
Below is a possible code to create variable for template path:
from django import template
register = template.Library()
#register.simple_tag
def build_template_path(base, name):
return base.format(name)
base in your case would be "paintings/experiments/points/{}.html" and name would be source.name.
Now in the template you first have to load these custom tags with:
{% load custom_tags %}
and then you use this template tag in the template:
{% for source in sources %}
{% build_template_path "paintings/experiments/points/{}.html" source.name as template_path %}
{% include template_path %}
{% endfor %}
With build_template_path you create custom variable template_path which you then use in the include tag.
Overall, template tags are very powerful. You can create or do pretty much anything with them, while filters are a bit more limited, but you could have done that with filters as well. Maybe something like this:
#register.filter
def replace_value(value, name):
return value.replace('**', name)
{% include "paintings/experiments/points/**.html"|replace_value:source.name %}

NoReverseMatch encountered when importing one Django template into another

In a Django project, I have a mini navbar that is common in ~30% of my templates. Instead of including it in my global base.html, I decided to take a different route.
I first wrote a separate view for this:
from django.template.loader import render_to_string
def navbar(origin=None):
if origin == '1':
locations = get_approved_loc(withscores=True)
else:
locations = get_approved_loc()
obj_count = get_all_obj_count()
return render_to_string("mini_navbar.html",{'top_3_locs':locations[:3],\
'other_cities':len(locations[3:]),'obj_count':obj_count})
I next added it in the templates it needed to be in via:
{% include "mini_navbar.html" with origin='1' %}
When I run this code, I get a NoReverseMatch error. It seems the view function navbar never runs. So the context variables it was sending in (e.g. top_3_locs or other_cities etc) are never populated. Hence NoReverseMatch.
What's wrong with this pattern, and what's the fix for it? An illustrative example would do the trick.
Rather than including a template directly, you should write a custom template tag - specifically, an inclusion tag that renders the template with the custom context. The code that you have put in that separate view goes in that template tag instead.
Here's an illustrative example of Daniel's suggestion:
I created an 'inclusion' template tag like so:
from django import template
from redis_modules import get_approved_loc, get_all_obj_coun
register = template.Library()
#register.inclusion_tag(file_name='mini_navbar.html')
def mini_navbar(origin=None):
locations = get_approved_loc(withscores=True)
obj_count = get_all_obj_count()
return {'top_3_locs':locations[:3],'origin':origin,'other_cities':len(locations[3:]),'obj_count':obj_count}
Next I included this in the relevants templates like so:
{% load get_mini_navbar %} <!-- name of the module -->
And finally, I called it within the template like so:
{% mini_navbar origin %}
Where origin is the parameter passed into the tag.

How do I set a template argument value to the value of another tag?

I have a template tag to generate the url as follows;
<li>Archive</li>
I want the '2013'(year) to be generated automatically based off the current year. There is a tag that can do this {% now 'Y' %} however i cannot use it inside the existing template tag as it just produces errors.
Do i need to create a custom tag to do this?
May be better decision is would be set default parameter at the urls.py ?
Example urls.py:
from django.utils.timezone import now
...
urlpatterns = patterns('app.views',
url(r'^.../$', 'blog_archive', {'year': now().strftime('%Y')}),
)
It is not possible to include one tag inside another like this.
You can create an assignment tag, which stores the tag's result in a context variable instead of outputting it.
The example assignment tag in the docs is for a template tag get_current_time, which you could use instead of the {% now %} tag.
In your mytags.py template tag module:
from django import template
register = template.Library()
#register.assignment_tag
def get_current_time(format_string):
return datetime.datetime.now().strftime(format_string)
In your template:
{% load mytags %}
{% get_current_time "%Y" as year %}
<li>Archive</li>
That is what you want.
Maybe this:
<li>Archive</li>
# just pass the datetime object as 'value'

django - template tag problem using AuthenticationForm

I am trying to put a login form in every page in my web that uses django.contrib.auth.views.login. I created a templatetag in templatetags/mytags.py, where I define a function called get_login wich looks like this:
#register.inclusion_tag('registration/login.html', takes_context=True)
def get_login(context):
...
return {'formLogin': mark_safe(AuthenticationForm())}
...and in base.html:
{% load mytags %}{% get_login %}
The problem now is that the template (registration/login.html) doesnt recognize {{ formLogin.username }},{{ formLogin.password }}... and so on.
What am I missing?
mark_safe returns an instance of django.utils.safestring.SafeString, not a form, so those lookups will fail. I don't think there's anything wrong with directly returning the form (that's what all the generic views in django.contrib.auth do when populating templates, for instance). Just change your return statement to
return {'formLogin': AuthenticationForm()}
and it should work.

How to render a high-score in base.html

So we're writing a super simple game-app (answer questions, get points) and we want to render a high-score in the side-bar of every screen on the page.
So I understand that Django automatically (kinda) passes the authenticated user as argument (if we use render() ) but I'm not sure how to pass what basically will be:
top_list = User.objects.filter().order_by('-score')[:10]
so that we can fix a nice little top list in our base template :)
We've looked around at different questions here, like this one for example and thought about whether the solution would be to write our own context processor?
EDIT:
Might be a duplicate of this so should I perhaps write a custom template tag instead?
You can use django template tags to do it..
Under myapp/templatetags/ create a myapp_tags.py and __init__.py
In myapp_tags.py do the following:
from django import template
register = template.Library()
#register.assignment_tag
def get_top_list():
top_list = User.objects.filter().order_by('-score')[:10]
return top_list
And then use it in your templates like this:
{% load myapp_tags %}
{% get_top_list as top_list %}
{% for top_user in top_list %}
...