Django - Liste index in template - python

I have a problem with my template.
I know how to use list.index to get a value from a list, but now my index value is list.container.id (=1).
So, I have stupidly try list.container.id and is not working like list.1.

Edit: As pointed out the old answer was wrong,
New Solution:
Create a custom filter tag.
In your app, create a python module called templatetags (create a folder and place an init.py file in it) then create a py file for your custom filter, for ex: my_custom_filter.py
from django import template
register = template.Library()
#register.filter
def index_my_list(my_list, index):
try:
return my_list[index]
except IndexError:
return None
Use in your template as
{{list|index_my_list:container.id}}
All this being said, it is best to keep your logical code in the view, you might want to reconsider your data structures
Wrong Solution:
Assign container.id to a variable then use it
{% with container.id as foo %}
{{list.foo}}

Related

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 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.

Locating lower level templates

Hi I am having problems with the template using Bottle
my folder structure is this:
|views
--main.tpl
--|blog
--home.tpl
what I want to do is this:
def home():
return template('blog/home')
but it won't work
I can get it to work just calling the following:
def home():
return template('main')
But I want to be-able to have many different folders
I understand that I will still need to keep unique names because of the caching
and please don't say use a different framework as this is not my choice.
You can try passing the template_lookup argument to the template function. template_lookup overrides the defaults .views path when looking for the template. However I believe this will only work if the name of the tempalte is not in the views folder. So if you had a /views/main.tpl and a /blog/main.tpl it would not work, every template needs a unique name. This is needed because bottle will only lookup search for tempaltes if it hasn't found it before and stores the found ones in a dict with the tempalte name as the key. so if the templates have the same name it would use the first one.
return template("home", template_lookup="full_path_to/views/blog/"

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.

Using Django view variables inside templates

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')

Categories