Using Django view variables inside templates - python

this is a rather basic question (I'm new to Django) but I'm having trouble using a variable set in my view inside my template. If I initialize a string or list inside my view (i.e. h = "hello") and then attempt to call it inside a template:
{{ h }}
there is neither output nor errors. Similarly, if I try to use a variable inside my template that doesn't exist:
{{ asdfdsadf }}
there is again no error reported. Is this normal? And how can I use my variables within my templates. Thanks!

In order to have access to a variable in a template, it needs to be in the the context used to render that template. My guess is you aren't passing a context dictionary to the template when you render it.
http://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render-to-response
The "dictionary" referenced there is a dictionary that contains all the variables you want to have available in the context. For example:
return render_to_response('your_template.html', {'h': h})
As far as the "no error" error goes... That's the default setting for an invalid template variable. You can change that in the project's settings if you'd like.
http://docs.djangoproject.com/en/dev/ref/settings/#template-string-if-invalid

You can also use
return render(request, 'your_template.html', {'h':h, 'var1':var1})
Refer to the latest manual on https://docs.djangoproject.com/es/1.9/topics/http/shortcuts/

Yes! This is normal. Such errors in templates fail silently and this is expected in Django.
to render properly template use render_to_response('your_template.html', {'h':h}) (there is also a nasty shortcut render_to_response('your_template.html', locals()) if your context dictionary is very big)
here is some explanation with examples: http://www.djangobook.com/en/beta/chapter04/ (section 'How invalid variables are handled')

Related

How to get template variable from within a custom template tag

In Django, is there a way for a custom template tag to have access to the current template's variables passed on by the view?
My first thought is to make a parameter where the user can place the template variable manually but if my custom template tag can access the variable itself then it would be much better!
To illustrate, I want to get rid of the parameter templatevar
#register.simple_tag
def sampletag(templatevar):
return templatevar
You can use the takes_context parameter to the decorator.
#register.simple_tag(takes_context=True)
def sampletag(context):
return context['templatevar']
See the template tags documentation.

Get list of variables from Jinja2 template (parent and child)

I'm trying to get a list of variables from a Jinja2 template.
test1.j2:
some-non-relevant-content
{{var1}}
{% include 'test2.j2' %}
test2.j2:
another-text
{{var2}}
I can get variables from test1 easily:
env = Environment(loader=FileSystemLoader(searchpath='./Templates'))
src_t = env.loader.get_source(env, 'test1.j2')[0]
parsed_t = env.parse(source=src_t)
t_vars = meta.find_undeclared_variables(ast=parsed_t)
Problem is, I can only get variables from the parent template with get_source.
Obviously, I can not feed class template object to parse method as well.
Is there any way to build the full list? {'var1', 'var2'} in my case.
Ideally by using Jinja2 API. Minimum custom code.
Found a way to code that without a big pain.
meta.find_referenced_templates helps to load all child templates when applied recursively. When done, it's trivial to get variables from all templates in a single list.

Django - how to pass object to a template with a class based view?

I'm switching over to class based views in my project for most of my views just because they are less repeated code, and I can't figure out how to pass an object to a template. By default using a detail view passes the object, which is fine for accessing direct attributes of it, but my objects have tags on them that are defined via an extension and accessed via a function of that extension. In my old function based view, I would get the list of tags and pass it to the template like this to be iterated over:
return render(request, "gallerypage.html", {
'gallery': gallery,
'tags': gallery.misc_tags.names(),
'form': form
})
My new view looks like this:
class GalleryView(DetailView):
model = Gallery
template_name = 'gallerypage.html'
urls.py:
urlpatterns = patterns('',
url(r'^(?P<pk>\d+)/$', GalleryView.as_view(), name='show_gallery'),
url(r'^(?P<pk>\d+)/edit/$', GalleryUpdate.as_view(), name='update_gallery',),
)
The gallery object is passed to the template fine, and I can access attributes of it, for example the name, by using something like <h1>{{ object.name }}</h1>. But seeing as it isn't a good idea to try running arbitrary Python code in templates, I need a better way to pass the tags object into the template so I can display them, as something like
{{ object.misc_tags.names()|join:", " }}
right in it will not work. Thanks
You could override get_context_data and add any additional context you want. This method is often overriden in CBV's
Calling object.misc_tags.names without the parentheses would implicitly call the function. Alternatively use get_context_data like dm03514 had suggested.
From the django docs on periods in templates:
Technically, when the template system encounters a dot, it tries the following lookups, in this order:
Dictionary lookup
Attribute lookup
Method call
List-index lookup

django get first part of a string

Is there a simple django tag to get the first x characters of a string in a template?
In a list of modelinstances, I would like to give a different symbol per objectinstance, depending on the status of the objectinstance. Status could be 'waiting', 'success' or 'failed XXXX', with XXXX being the errorcode.
I would like to check if the first 5 characters of objectinstance.status == 'error', then the symbol will be red. However, how can I do this? In Python I could use objectinstance.status[:5].
Using https://docs.djangoproject.com/en/dev/ref/templates/builtins/ I managed to do this with following 'monstruous' concatenation, but is there something simple as .left() or .right()?
{% if run.status|make_list|slice:":5"|join:"" == 'error' %}
You could try:
{% if run.status|truncatechars:5 == 'error...' %}
(See truncatechars in the Django docs)
Although I might say, as an overall point, you shouldn't be putting this kind of logic in your Django templates (views in other frameworks). You want to put this into the Django view (controller in other framerworks). Meaning, you would something like this in your view:
has_error = run.status.startswith('error')
Ensure has_error is passed to the template and:
{% if has_error %}
It may be more work, but the logic to detect error conditions could be shared between multiple views and templates, and you separate control logic from view logic.
If you use Django 1.4+ you can use the truncatechars tag but it will only solve partially your answer and will add ellipsis at the end.
The only viable way, a part from concatenating many filters as you already did, is to write a custom filter. Here is a first draft you can customize:
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter
#stringfilter
def slicestring(value, arg):
"""usage: "mylongstring"|slicestring:"2:4" """
els = map(int, arg.split(':'))
return value[els[0]:els[1]]
as a bonus this filter allows you to mimic almost completely the slice notation by providing a "slicing string" as the argument. The only exception seems the syntax [:9] that has to be replaced with [0:9], thus with this argument: yourvariable|slicestring:"0:9"
A side note: Since your question is "getting the first part of a string" I believe a custom filter may be the correct answer, however if the only reason to get a sliced string is to check for a part of it inside an if statement, then I have to agree with Anton: you should place your checks inside the view, not inside the template, when possible.

Jinja2: Looking for a View-Helper

I'am new to the Jinja2 template engine. Is there something like the view-helpers from Zend Framework? Can i create simple functions and reuse them all over all my template-files?
Something like this?
#somewhere in my python code:
def nice_demo_function(message):
""""return a simple message"""
return message
So i can to use that:
<!-- now in my template-file -->
{% nice_demo_function('yes, this works great!') %}
There are a number of ways you can expose helper functions to your templates. You could define them using macros, and then import them into templates that use them. You could add functions to the globals attribute of your Template objects, or pass them to the render() method. You could subclass Template to do the same without having to repeat yourself each time. If you want to get really fancy, you could look into writing extensions as well (but you probably don't need to go that deep).
At some point you will have created a Jinja2 environment. The environment has an attribute on it called filters which is a dict that maps names to functions. So what you want to do is:
def my_helper(value):
return "-~*#--- %s ---#*~-" % value
env = Jinja2.Environment(...)
env.filters['my_helper'] = my_helper
Now in your template you can do:
<p>The winner is {{ winner | my_helper }}</p>
And your function will be called with the value of the variable, in this case winner. If you are using Pylons, this all happens in config/environment.py.

Categories