I`m new with django (came from Grails), especially with all those custom tags that you have to deal with, instead of writing your variables directly inside the templates.
Well, what I need to do was something really simple, but for some reason is taking me a long time to finish. What I wish to do was make a tag that checks for me if the given path is equals my current url, and then returns the class if true.
<li class="{% check_url '/login/' 'current_page_item' %}">
login
</li>
But, the problem came when I tried to register the tag with takes_context :
Caught TypeError while rendering: simple_tag() got an unexpected keyword argument 'takes_context'
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def check_url(context, path, attr):
if context['request'].environ.get('PATH_INFO') == path:
return attr
else:
return ''
How can I fix it? Also, is there a better way to do it?
That's because takes_context is only available since django 1.3.
Another approach to do it (and to avoid hardcoded urls):
{% url social_login as the_url %}
{% ifequal the_url request.path %}
....
{% endif %}
Or check out something like this!
Related
Hi I want to check if my variable is numeric in Django template
and I tried this code
{% if isnumeric(item) %}
<h1>{{item}}</h1>
{% endif %}
but this throws me this error
Could not parse the remainder: '(item)' from 'isnumeric(item)'
I tried to find a builtin template tag or filter in this page
https://docs.djangoproject.com/en/3.1/ref/templates/builtins/ of Django document
and I searched for this question in StackOverflow too
but I did not found anything related
I don't believe there's a built in template function to check for that. One way to do it is to write your own:
https://docs.djangoproject.com/en/3.1/howto/custom-template-tags/
The code would look something like:
my_filters.py
from django import template
register = template.Library()
#register.filter()
def is_numberic(value):
return value.isdigit()
And in the html:
{% load my_filters %}
{% if item|is_numeric %}
...
isnumeric() python fuction doesn't take any parameters
Make a fuction in your model:
def isnumeric(self):
item = self.item
if item.isnumeric() is True:
return True
else:
return False
then in your template:
{% if item.isnumeric %}
<h1>{{item}}</h1>
{% endif %}
With this, you can use the isnumeric() function in your template. You can add an else statement too.
Take a look to isnumeric() function
Working with Django 1.5.5 I need to call a custom templatetag and somehow store the result in a variable, to check if it contains a non empty empty string. I need something that should look like:
{% load smart_html %}
{% render_html widget.content as widget_content %}
{% if widget_content %}
Do stuff here...
{% endif %}
This is inspired on the {% url %} built-in templatetag that allows calling it storing the result in a variable using the syntax:
{% url 'named_url' as my_named_url %}
My templatetag looks like:
#register.simple_tag(takes_context=True)
def render_html(context, html):
"""Allows executing 'Django code' within the HTML"""
return Template(html).render(context)
I also thought about adding the returned value from the custom templatetag to the context. What do you think about this? Would this be dangerous? This would look like:
#register.simple_tag(takes_context=True)
def render_html(context, html, var_name=None):
"""Allows executing 'Django code' within the HTML"""
html = Template(html).render(context)
if var_name:
context[var_name] = html
html = ''
return html
If the tag is something you control, then perhaps consider using an assignment tag. If the tag isn't something you control, then you might have to wrap it with an assignment tag of your own.
#register.assignment_tag(takes_context=True)
def render_html(context, content):
return Template(content).render(context)
But I don't know what you are trying to achieve? Isn't it better to do this kind of stuff in your view function and based on the result call different templates with TemplateResponse?
Django says there's 3 ways to turn off autoescape:
Use |safe after the variable
Use {% autoescape on %} and {% endautoescape %} within blocks
Use a Context like context = Context({'message': message}, autoescape=False)
(1) and (2) work fine. But I have the situation where I have templates to generate plain-text push notifications, and I have LOADS of templates to build and maintain. I could go through and put the {% autoescape on %} and {% endautoescape %} tags in all of them, but (3) should allow me to do it in one line in the view.
The template:
{% block ios_message %}{{message}}{% endblock %}
The view:
message = u"'&<>"
context = Context({'message': message}, autoescape=False)
render_block_to_string(template_name, 'ios_message', context)
The output:
u''&<>
The code for block_render.py is from here: https://github.com/uniphil/Django-Block-Render/blob/master/block_render.py. I'm using it as is from there.
Anyone know what gives?
Take a closer look to function render_block_to_string():
def render_block_to_string(template_name, block, dictionary=None,
context_instance=None):
"""Return a string
Loads the given template_name and renders the given block with the
given dictionary as context.
"""
dictionary = dictionary or {}
t = _get_template(template_name)
if context_instance:
context_instance.update(dictionary)
else:
context_instance = Context(dictionary)
return render_template_block(t, block, context_instance)
The 3rd arg should be a dict, not context. Otherwise it would use the normal context instance.
So I believe it should be:
render_block_to_string(template_name, 'ios_message', {}, context)
Hope it helps.
I could solve it my doing it like that:
from django.template.context import make_context
from django.template.loader import get_template
# Getting the template either by a path or creating the Template object yourself
template = get_template('your/path/to/the/template.html')
# Note here the 'template.template' and the 'autoescape=False' parameter
subject = template.template.render(make_context(context, autoescape=False))
Found it by doing that myself. Because by default the autoescape setting will be used from the engine
https://github.com/django/django/blob/4b6dfe16226a81fea464ac5f77942f4d6ba266e8/django/template/backends/django.py#L58-L63
Django Version: 2.2.1
Wanted to comment but looks like I don't have enough reputation since this is a newish account
You can turn off the autoescape found here: https://github.com/django/django/blob/529c3f264d99fff0129cb6afbe4be2eb11d8a501/django/template/context.py#L137
i.e.
Context(data_dict, autoescape=False)
I'm implementing a custom permissions application in my Django project, and I'm lost as to how to implement a custom template tag that checks a logged in user's permissions for a specific object instance and shows a piece of HTML based on the outcome of the check.
What I have now is (pseudocode):
{% check_permission request.user "can_edit" on article %}
<form>...</form>
{% endcheck %}
('check_permission' is my custom template tag).
The templatetag takes in the user, the permission and the object instance and returns the enclosed HTML (the form). This currently works fine.
What I would like to do however, is something like:
{% if check_permission request.user "can_edit" on article %}
<form>...</form>
{% else %}
{{ article }}
{% endif %}
I've read about the assignment tag, but my fear is that I would pollute the context variable space with this (meaning I might overwrite previous permission context variables). In other words, as the context variables are being defined on different levels (the view, middleware in my case, and now this assignment template tag), I'm worried about maintainability.
You can use template filters inside if statements. So you could rewrite your tag as a filter:
{% if request.user|check_can_edit:article %}
Note that it's tricky to pass multiple arguments of different types to a filter, so you'll probably want to use one filter per permission, above I've used check_can_edit.
You can definitely do that if you're willing to write some more lines of python code to improve your template readability! :)
You need to parse the tag content yourself, even the parameters it takes and then resolve them, if you want to use variables on them.
The tag implemented below can be used like this:
{% load mytag %}
{% mytag True %}Hi{% else %}Hey{% endmytag %} Bro
Or with a variable:
{% mytag myobject.myflag %}Hi{% else %}Hey{% endmytag %} Bro
So, here's the way I did it:
from django.template import Library, Node, TemplateSyntaxError
register = Library()
#register.tag
def mytag(parser, token):
# Separating the tag name from the "test" parameter.
try:
tag, test = token.contents.split()
except (ValueError, TypeError):
raise TemplateSyntaxError(
"'%s' tag takes two parameters" % tag)
default_states = ['mytag', 'else']
end_tag = 'endmytag'
# Place to store the states and their values
states = {}
# Let's iterate over our context and find our tokens
while token.contents != end_tag:
current = token.contents
states[current.split()[0]] = parser.parse(default_states + [end_tag])
token = parser.next_token()
test_var = parser.compile_filter(test)
return MyNode(states, test_var)
class MyNode(Node):
def __init__(self, states, test_var):
self.states = states
self.test_var = test_var
def render(self, context):
# Resolving variables passed by the user
test_var = self.test_name.resolve(context, True)
# Rendering the right state. You can add a function call, use a
# library or whatever here to decide if the value is true or false.
is_true = bool(test_var)
return self.states[is_true and 'myvar' or 'else'].render(context)
And that's it. HTH.
In Django 2 the assignment tag was replaced by simple_tag() but you could store the custom tag result as a template variable:
# I'm assuming that check_permission receives user and article,
# checks if the user can edit the article and return True or False
{% check_permission user article as permission_cleared %}
{% if permission_cleared %}
<form>...</form>
{% else %}
{{ article }}
{% endif %}
Check the current doc about custom template tags: https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/#simple-tags
inside my_tags.py
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def make_my_variable_true(context):
context['my_variable'] = True
return '' # without this you'll get a "None" in your html
inside my_template.html
{% load my_tags %}
{% make_my_variable_true %}
{% if my_variable %}foo{% endif %}
In this case best solution is to use custom filter. If you don't want write long code for custom tag. Also if you don't want to copy/paste others code.
Here is an example
Inside templatetag
register = template.Library()
def exam_available(user, skill):
skill = get_object_or_404(Skill, id=skill)
return skill.exam_available(user)
register.filter('exam_available', exam_available)
Inside template
{{ request.user|exam:skill.id }}
or
{% if request.user|exam:skill.id %}
Since one of the main common of it is to use request.user or any specific object(id) inside model's custom method, so filtering that individual object or user is the easiest way to make it done. :)
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.