I use the 'messages' interface to pass messages to user like this:
request.user.message_set.create(message=message)
I would like to include html in my {{ message }} variable and render it without escaping the markup in the template.
If you don't want the HTML to be escaped, look at the safe filter and the autoescape tag:
safe:
{{ myhtml |safe }}
autoescape:
{% autoescape off %}
{{ myhtml }}
{% endautoescape %}
If you want to do something more complicated with your text you could create your own filter and do some magic before returning the html.
With a templatag file looking like this:
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
#register.filter
def do_something(title, content):
something = '<h1>%s</h1><p>%s</p>' % (title, content)
return mark_safe(something)
Then you could add this in your template file
<body>
...
{{ title|do_something:content }}
...
</body>
And this would give you a nice outcome.
Use the autoescape to turn HTML escaping off:
{% autoescape off %}{{ message }}{% endautoescape %}
You can render a template in your code like so:
from django.template import Context, Template
t = Template('This is your <span>{{ message }}</span>.')
c = Context({'message': 'Your message'})
html = t.render(c)
See the Django docs for further information.
The simplest way is to use the safe filter:
{{ message|safe }}
Check out the Django documentation for the safe filter for more information.
No need to use the filter or tag in template.
Just use format_html() to translate variable to html and Django will automatically turn escape off for you variable.
format_html("<h1>Hello</h1>")
Check out here https://docs.djangoproject.com/en/3.0/ref/utils/#django.utils.html.format_html
The safe filter did the work for me.
Using {{data|safe}} includes the html as it is.
Related
How can I access an attribute of an object using a variable? I have something like this:
{% for inscrito in inscritos %}
{% for field in list_fields_inscrito %}
{{inscrito.field}} //here is the problem
{% endfor %}
{% endfor %}
For example Inscrito have: inscrito.id, inscrito.Name and inscrito.Adress and I only want to print inscrito.id and inscrito.Name because id and Name are in the list_fields_inscrito.
Does anybody know how do this?
You can write a template filter for that:
myapp/templatetags/myapp_tags.py
from django import template
register = template.Library()
#register.filter
def get_obj_attr(obj, attr):
return getattr(obj, attr)
Then in template you can use it like this:
{% load myapp_tags %}
{% for inscrito in inscritos %}
{% for field in list_fields_inscrito %}
{{ inscrito|get_obj_attr:field }}
{% endfor %}
{% endfor %}
You can read more about writing custom template tags.
Fixed answer for non string attributes
The selected answer don't cover cases where you need to access non string attributes.
If you are trying to access an attribute that isn't a string, then you must use this code:
from django import template
register = template.Library()
#register.filter
def get_obj_attr(obj, attr):
return obj[attr]
For this, create a folder named templatetags on your app's folder, then create a python file with whatever name you want and paste the code above
inside.
Inside your template load your brand new filter using the {% load YOUR_FILE_NAME %}, be sure to change YOUR_FILE_NAME to your actual file name.
Now, on your template you can access the object attribute by using the code bellow:
{{ PUT_THE_NAME_OF_YOUR_OBJECT_HERE|get_obj_attr:PUT_THE_ATTRIBUTE_YOU_WANT_TO_ACCESS_HERE }}
I am trying to render an object in a template like what we can do with forms {{ form }} but the output is turned into text and not html code. How to really include html code?
my_object = MyObject()
{{ my_object }}
The class:
from django.template import Context, Template
from django.utils.safestring import mark_safe
class MyObject(object):
def __str__(self):
return self.render()
def render(self):
t = Template('<p>This is your <span>{{ message }}</span>.</p>')
c = Context({'message': 'Your message'})
html = t.render(c)
return mark_safe(html)
You should be implementing __unicode__ instead of __str__. The templating module stringifies context variables as unicode.
You can also use
{% autoescape off %}
{{ info }}
{% endautoescape off %}
But you must be care to avoid xss vulnerabilities.
If the attempt is to get html on to the page then you should be using {{myobject|safe}}. That should render the HTML code instead of text
Let's make this very easy for my fellow SOians(?).
This is how normally the custom template tags work -
Template ->
{% block content %}
blah blah blah
{% custom_tag_load %}
{% endblock %}
The custom_tag_load is called and it returns a string. What I want to return is a queryset which I could possibly use like this ->
{% block content %}
blah blah blah
{% for x in custom_tag_load %}
{{ x.datetime }}
{% endfor %}
{% endblock %}
Note -> What I'm basically trying to do is to avoid passing the queryset through the view, and I'm not sure if I should be comfortable storing querysets in my global context.
You can return anything you like from a tag, including a queryset. However, you can't use a tag inside the for tag - you can only use a variable there (or a variable passed through a filter). What you could do is get your tag to put the queryset into a variable in the context, and use that variable in the for loop. See the docs on how to set a variable from a tag - although note that the development version has an easier method for doing this.
However, you shouldn't be concerned about putting a queryset into a context processor, either. Don't forget that querysets are lazy, so no database hit will be made unless the queryset is evaluated or iterated in the template.
A template tag can do whatever you want. From your pseudo code, you could accomplish what you need with an inclusion tag:
#my_tags.py
from django import template
from my_app.models import MyModel
register = template.Library()
#register.inclusion_tag('my_template.html')
def my_custom_tag():
things = MyModel.objects.all()
return {'things' : things}
#my_template.html
{% if things %}
<ul>
{% for thing in things %}
<li>{{ thing }}</li>
{% empty %}
<li>Sorry, no things yet.</li>
{% endfor %}
</ul>
{% endif %}
#the_view.html
{% load my_tags %}
{% my_custom_tag %}
Alternatively, you could write a custom tag that adds a queryset to the context. Hope that helps you out.
I had these same problems recently and most of the answers here were kind of outdated, but a little digging through Django's documentation and I was able to sort it out.
Like most of the answers above, you can return basically anything using a template tag, but it all depends on how you register the template tags. So say you want to use a template tag to return a queryset to be available for any template you wish, you could register the template tag as a simple tag just like this
from django import template
from blog.models import Post
from django.template.defaulttags import register
register = template.Library()
#register.simple_tag
def get_posts():
return Post.objects.all()
Then to be able to access this in your template, you first need to load this file in your template like
{% load templatetagfile %}
And then to loop through, you need to first assign it to a variable before looping through
{% get_posts as posts %}
{% for post in posts %}
{{ post.whatever }}
{% endfor %}
The first line there makes the queryset from the get_posts function available as a variable named posts which you can then loop through.
I want to concatenate a string in a Django template tag, like:
{% extend shop/shop_name/base.html %}
Here shop_name is my variable and I want to concatenate this with rest of path.
Suppose I have shop_name=example.com and I want result to extend shop/example.com/base.html.
Use with:
{% with "shop/"|add:shop_name|add:"/base.html" as template %}
{% include template %}
{% endwith %}
Don't use add for strings, you should define a custom tag like this :
Create a file : <appname>\templatetags\<appname>_extras.py
from django import template
register = template.Library()
#register.filter
def addstr(arg1, arg2):
"""concatenate arg1 & arg2"""
return str(arg1) + str(arg2)
and then use it as #Steven says
{% load <appname>_extras %}
{% with "shop/"|addstr:shop_name|addstr:"/base.html" as template %}
{% include template %}
{% endwith %}
Reason for avoiding add:
According to the docs
This filter will first try to coerce both values to integers...
Strings that can be coerced to integers will be summed, not concatenated...
If both variables happen to be integers, the result would be unexpected.
I have changed the folder hierarchy
/shop/shop_name/base.html To /shop_name/shop/base.html
and then below would work.
{% extends shop_name|add:"/shop/base.html"%}
Now its able to extend the base.html page.
You do not need to write a custom tag. Just evaluate the vars next to each other.
"{{ shop name }}{{ other_path_var}}"
Refer to Concatenating Strings in Django Templates:
For earlier versions of Django:
{{ "Mary had a little"|stringformat:"s lamb." }}
"Mary had a little lamb."
Else:
{{ "Mary had a little"|add:" lamb." }}
"Mary had a little lamb."
Have a look at the add filter.
Edit: You can chain filters, so you could do "shop/"|add:shop_name|add:"/base.html". But that won't work because it is up to the template tag to evaluate filters in arguments, and extends doesn't.
I guess you can't do this within templates.
From the docs:
This tag can be used in two ways:
{% extends "base.html" %} (with quotes) uses the literal value "base.html" as the name of the parent template to extend.
{% 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.
So seems like you can't use a filter to manipulate the argument. In the calling view you have to either instantiate the ancestor template or create an string variable with the correct path and pass it with the context.
I found working with the {% with %} tag to be quite a hassle. Instead I created the following template tag, which should work on strings and integers.
from django import template
register = template.Library()
#register.filter
def concat_string(value_1, value_2):
return str(value_1) + str(value_2)
Then load the template tag in your template at the top using the following:
{% load concat_string %}
You can then use it the following way:
123
I personally found this to be a lot cleaner to work with.
How about this! We have first_name and last_name, which we want to display space " " separated.
{% with first_name|add:' '|add:last_name as name %}
<h1>{{ name }}</h1>
{% endwith %}
What we're actually doing is: first_name + ' ' + last_name
#error's answer is fundamentally right, you should be using a template tag for this. However, I prefer a slightly more generic template tag that I can use to perform any kind of operations similar to this:
from django import template
register = template.Library()
#register.tag(name='captureas')
def do_captureas(parser, token):
"""
Capture content for re-use throughout a template.
particularly handy for use within social meta fields
that are virtually identical.
"""
try:
tag_name, args = token.contents.split(None, 1)
except ValueError:
raise template.TemplateSyntaxError("'captureas' node requires a variable name.")
nodelist = parser.parse(('endcaptureas',))
parser.delete_first_token()
return CaptureasNode(nodelist, args)
class CaptureasNode(template.Node):
def __init__(self, nodelist, varname):
self.nodelist = nodelist
self.varname = varname
def render(self, context):
output = self.nodelist.render(context)
context[self.varname] = output
return ''
and then you can use it like this in your template:
{% captureas template %}shop/{{ shop_name }}/base.html{% endcaptureas %}
{% include template %}
As the comment mentions, this template tag is particularly useful for information that is repeatable throughout a template but requires logic and other things that will bung up your templates, or in instances where you want to re-use data passed between templates through blocks:
{% captureas meta_title %}{% spaceless %}{% block meta_title %}
{% if self.title %}{{ self.title }}{% endif %}
{% endblock %}{% endspaceless %} - DEFAULT WEBSITE NAME
{% endcaptureas %}
and then:
<title>{{ meta_title }}</title>
<meta property="og:title" content="{{ meta_title }}" />
<meta itemprop="name" content="{{ meta_title }}">
<meta name="twitter:title" content="{{ meta_title }}">
Credit for the captureas tag is due here: https://www.djangosnippets.org/snippets/545/
And multiple concatenation:
from django import template
register = template.Library()
#register.simple_tag
def concat_all(*args):
"""concatenate all args"""
return ''.join(map(str, args))
And in Template:
{% concat_all 'x' 'y' another_var as string_result %}
concatenated string: {{ string_result }}
You can't do variable manipulation in django templates.
You have two options, either write your own template tag or do this in view,
extends has no facility for this. Either put the entire template path in a context variable and use that, or copy the exist template tag and modify it appropriately.
In my project I did it like this:
#register.simple_tag()
def format_string(string: str, *args: str) -> str:
"""
Adds [args] values to [string]
String format [string]: "Drew %s dad's %s dead."
Function call in template: {% format_string string "Dodd's" "dog's" %}
Result: "Drew Dodd's dad's dog's dead."
"""
return string % args
Here, the string you want concatenate and the args can come from the view, for example.
In template and using your case:
{% format_string 'shop/%s/base.html' shop_name as template %}
{% include template %}
The nice part is that format_string can be reused for any type of string formatting in templates
In my case I needed to concatenate to send a string concatenated by parameter to a simple_tag and I didn't need the with, which saves 2 lines:
{% method firstParam "stringSecondParam="|add:valueSecondParam thirdParam as result %}
In this case the solution to the problem would be: "string="|add:object
I need to produce an id surrounded by braces ( for example "{1234}" ). With the django template language, braces are also used to start a variable substitution, so I have some trouble in obtaining what I want. I tried
{{{ id }}}
{{ '{'id'}' }}
{{ '{'+id+'}' }}
{ {{ id }} }
None of these methods work, except the last one, which unfortunately produces "{ 1234 }", not what I want. I currently have two solutions : either I pass an id variable already containing the {} (ugly) or I write a custom filter and then write {{ id|add_braces }} (I prefer it).
Before going this way, I prefer to ask if a better solution exists.
Using escaped values does not work. Even if I add {% autoescape off %}%7B{% endautoescape %} I don't get the {, which is strange, but that's another problem.
Thanks
Edit: I wrote a quick filter. Pasting it here so someone else can use it as a template for writing a more complex one. To be put into python package application_path/templatetags/formatting.py
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter
#stringfilter
def add_braces(value):
return "{"+value+"}"
I think your answer can be found here:
http://docs.djangoproject.com/en/dev/ref/templates/builtins/#templatetag
In short, you want to use {% templatetag openbrace %} and {% templatetag closebrace %}.
Edit:
Django now also includes this functionality out of the box:
{% verbatim %} {{ blah blah }} {% endverbatim %}
{% templatetag openbrace %} become extremely verbose for e.g. javascript templates
I've used the verbatim tag from this gist with some success for exactly this purpose which lets you do something like
{{ request.user }}
{% verbatim %}
brackets inside here are left alone, which is handy for e.g. jquery templates
{{ this will be left }}
{% so will this %}
{% endverbatim }}
{% more regular tags (to be replaced by the django template engine %}
The recommendation from the Jinja templating language works with the Django templating engine as well:
http://jinja.pocoo.org/docs/dev/templates/#escaping
The solution is this:
{{ '{' }}{{ id }}{{ '}' }}
Of course the other two answers work, but this is one is less verbose and more readable, in my opinion.