I'm trying to access some data in a template. I don't think the way I'm doing it now is the best way, but I can't get it even half working any other way.
def room(request, room_id):
#get room data
room = Room.objects.filter(id=room_id).get()
modules = []
#pull all actuator devices for the room
actuators = Device.objects.filter(room_id=room_id,type="actuator")
#build a list of modules then use set to remove duplicates
for actuator in actuators.values():
module = Module.objects.get(module_id=actuator["module_id"]).name_only()
modules.extend([module])
modlist = list(set(modules))
moduleData = {}
#loop through the modules, pull out the required data and send it all off to the template
for module in modlist:
data = Module_List.objects.get(name=module)
dict = {"name": data.name, "widget_mqtt_js": data.widget_mqtt_js, "widget_setup_js": data.widget_setup_js, "widget_body": data.widget_body}
moduleData[module] = dict
print dict["widget_mqtt_js"]
context = {"room_name" : room.name, "actuators" : actuators, "modules" : moduleData}
return render(request, 'control/room.html', context)
This is my code as it stands. The problem I'm having is that the loop in my template is returning blank. It looks like this:
{% for module in modules %}
{{module.widget_mqtt_js}}
{% endfor %}
I think there will be a way to do it with the Module_List model, but I could't get that working either..
modules in the template context is moduleData in your view code. But moduleData is a dict, and iterating over a dict yields its keys, not its values.
You need to iterate over the values, try:
{% for module in modules.values %}
{{module.widget_mqtt_js}}
{% endfor %}
Related
I'm trying to display a values from mongo database in web application. I'm using flask framework where I'm calling function which will return lists to print in a html template. My code is as bellow
dic = mycol.find(myquery)
This will contents dictionary object querying from mongodatabase
When I loop over this object I get dictionary set
for x in dic:
like each value of x contains
{'name':'john','age':'15','weight':'50'}
{'name':'ash','age':'18','weight':'60'}
{'name':'tim','age':'20','weight':'80'}
Code which I'm using for rendering these values as below
person_name = []
person_age = []
person_weight = []
for x in dic:
person_name.append(x["person_name"])
person_age.append(x["person_age"])
person_weight.append(x["person_weight"])
later I'm returning these lists for printing in html
jinja 2 code is as below
{{person_name[loop.index0]}} {{person_age[loop.index0]}} {{person_weight[loop.index0]}}
I feel this is not better approach to do this way. So is there any other better approach to do this in a very few line of code? Thanks for reading
If you're using flask you can simply pass a list or dictionary to the HTML template using the render_template() flask function.
In your case you can simply do (using this as an example). Note, where dictionary=dic is written, the first dictionary can be any name / variable, which you will then reference in the Jinja2 syntax.
#app.route('/')
def index():
# Code to get dictionary from db, assigned to dic like yours
return render_template('[name of template].html', dictionary=dic)
Then inside your template you can use Jinja2 syntax to do a for loop to list through the dic dictionary / list.
// Somewhere inside HTML template
{% for x in dictionary %}
<p>{{ x.name }}</p>
<p>{{ x.age }}</p>
<p>{{ x.weight }}</p>
{% endfor %}
I've got modules that if enabled/disabled would require a different arrangement of tables and iframes on the frontend webpage. In order to do this I set up a function to check which modules are enabled/disabled and assigned a number to each 'set' and will be created separate templates for each "set1.html", "set2.html", "set3.html", etc...
I'd like to utilize one single view where I can pass the set number from from function I created but I can't seem to figure out how.
def homeset(request):
return render(request, 'app/set1.html', {})
Looking to figure out some way to make the "1" the return of the function I created to determine which set# to load as template and would prefer to not have to create a view for every single template needed.
Just taking a stab at this, do you have a problem with setting the template name before rendering?
def homeset(request):
# define 'my_set'
# define num
...
my_template_name = None
if num in my_set:
my_template_name = 'app/set{}.html'.format(num)
return render(request, my_template_name)
Looks like Scott Skiles answered your question, but an alternative way is to use a single base template and the "include" templatetag.
You can pass the set number to the template and use the "if" templatetag" to include the content from appropriate template(s) for each set number.
{% if set_num == 1 %}
{% include "foo/bar.html" %}
{% elif set_num == 2 %}
{% include "foo/two.html" %}
{% endif %}
I am interested in rendering a template in multiple steps or keeping the tags for the undefined variables in Jinja2. I believe this would mean not only creating the 'UndefinedSilent" class (so the template won't crash on missing data) but also keeping the tags with the appropriate variable names if they are missing.
Example:
Let's say we have the name = "Test" included in the context, but quantity is missing.
Givent the following template:
<p>{{name}} has {{quantity}}</p>
After rendering, I need the template to become:
<p>test has {{quantity}}</p>
Does anyone know if this is achievable?
Providing DebugUndefined to named parameter undefined in the env, apparently does the trick. The rendered template preserves the {{<undefined variable}}.
Like here:
from jinja2 import Environment, BaseLoader, DebugUndefined
rtemplate = Environment(loader=BaseLoader,undefined=DebugUndefined).from_string("{{ a }} is defined, but {{ b}} is undefined")
print(rtemplate.render({"a":"a"}))
The result is:
a is defined, but {{ b }} is undefined
It is achievable using the default built-in filter.
<p>{{name|default('{{name}}')}} has {{quantity|default('{{quantity}}')}}</p>
The drawback is that the code becomes uglier and the variable names are duplicated, thus reducing maintainability.
Here is another approach that preserves undefined double curly expressions after rendering, including those that contain "multilevel" (dot-notated) references as well as any others.
The answer provided by Willy Pregliasco does not support preservation of undefined list types, eg {{ some_list[4] }} which is something I required. The below solution addresses this, as well as all possible schema types.
The idea is to parse the input template and try to resolve each expression with the provided context. Any that can not be resolved, we replace with a double curly expression that simply resolves to the original expression as a string.
Pass your template and context through the below preserve_undefineds_in_template function before calling render:
from jinja2 import Template, StrictUndefined, UndefinedError
import re
def preserve_undefineds_in_template(template, context):
patt = re.compile(r'(\{\{[^\{]*\}\})')
j2_expressions = patt.findall(template)
for j2_expression in set(j2_expressions):
try:
Template(j2_expression, undefined=StrictUndefined).render(context)
except UndefinedError:
template = template.replace(j2_expression, f"{{% raw %}}{j2_expression}{{% endraw %}}")
return template
Example:
template = """hello {{ name }}, {{ preserve_me }} {{ preserve.me[2] }}"""
context = { "name": "Alice" }
# pass it through the preserver function
template = preserve_undefineds_in_template(template, context)
# template is now:
# hello {{ name }}, {% raw %}{{ preserve.me }}{% endraw %} {% raw %}{{ preserve.me.too[0] }}{% endraw %}
# render the new template as normal
result = Template(template).render(context)
print(result)
The output is:
hello Alice, {{ preserve_me }} {{ preserve.me[2] }}
I also wated the same behaviour. The library jinja2schema provides the schema of variables needed for your template.
The steps for my solution are:
have a template
obtain the schema structure
give some data to fill
complete de data filling the missing items with the original string
from jinja2 import Template
import jinja2schema
def assign(schema, data, root=''):
'''Returns a corrected data with untouched missing fields
'''
out = {}
for key in schema.keys():
if isinstance(schema[key], (str, jinja2schema.model.Scalar)):
try:
out[key] = data[key]
except:
out[key] = f'{{{{ {root+key} }}}}'
elif isinstance(schema[key], (dict, jinja2schema.model.Dictionary)):
out[key]={}
try:
data[key]
except:
data[key] = {}
out[key] = assign(schema[key], data[key], root+key+'.')
return out
# original template
template_str = '<p>{{name}} has {{quantity}}</p>'
# read schema
schema = jinja2schema.infer(template_str)
# available data
data = {'name':'test'}
# data autocompleted
data_corrected = assign(schema, data)
# render
template = Template(template_str)
print(template.render(data_corrected))
The output is
<p>test has {{ quantity }}</p>
That was the intended result.
Hope it will help. This solution doesn't work with lists, but I think it is possible to extend the solution. You can also obtain the list of missing fields, if you need them.
This is the version with Template rather than Environment:
from jinja2 import Template, DebugUndefined
template = Template("<p>{{name}} has {{quantity}}</p>", undefined=DebugUndefined)
new_template = Template(template.render(name="Test"))
Thanks #giwyni
Another little hack if you just have few variables:
<p>{{name}} has {{ "{{quantity}}" }}</p>
The second replacement will replace to {{quantity}} so all is good ;)
My template has if/else functionality to handle displaying buttons on a page, I've managed to add an elif statement that displays the buttons only if an element in a mongo database is not one of three values. I'm trying to clean this up as the elif appears four times across two jinja2 templates. My code which works now looks like this:
{% elif (
('string1' not in database.category) and ('string2' not in database.category) and
('string3' not in database.category)) %}
I've tried declaring a tuple and doing a:
{% set hidebuttons = ['string1' , 'string2' , 'string3'] %} //sets tuple
{% elif not database.category in hidebuttons %} // checks if value not in tuple
and plenty of other methods to make this work but every time I reload the web page i keep seeing the buttons when i shouldn't be. Any advice is greatly appreciated.
I believe this should be in your view, not your template. If you need to do the query in more then one place, you can create a utility function that gets the results you need, then in your views, you can call the function and pass the data as context to your templates
if you're using a view_config decorator to render template, it could be something like:
#view_config(renderer='templates/foo.pt')
def my_view(request):
show_buttons = logic_to_determine_should_buttons_be_shown()
return {'show_buttons': show_buttons }
# your template
{% if show_buttons %}
show buttons
{% endif %}
I am new to python and django and was wondering how I would go about making a dict of lists.
My 4 lists are;
ap = request.POST.getlist('amount_paid[]')
pd = request.POST.getlist('paid_date[]')
method = request.POST.getlist('method[]')
comments = request.POST.getlist('comments[]')
How would I make that into a dictionary I could then loop over in a django template such as;
{% for i in the_dict %}
{{i.amount_paid}}
{% endfor %}
Thanks in advance!
Update:
hmm I not sure I posted my question properly. In php, I can do the following on an array of fields:
for($i=0;$i<count($_POST['amount_paid']);$i++) {
echo $_POST['amount_paid'][$i];
echo $_POST['paid_date'][$i];
}
All the form fields are input text fields.. How would I do this in Django?
Python's dict syntax is very simple. It's just key-value pairs inside a pair of curly braces, like this:
the_dict = {
'amount_paid': request.POST.getlist('amount_paid[]'),
'paid_date': request.POST.getlist('paid_date[]'),
'method': request.POST.getlist('method[]'),
'comments': request.POST.getlist('comments[]'),
}
Following your update, it looks like you don't want a dict at all but zip():
post = request.POST
lists = zip(post.getlist('amount_paid[]'),
post.getlist('paid_date[]'),
post.getlist('method[]'),
post.getlist('comments[]'),
)
for amount_paid, paid_date, method, comments in lists:
print amount_paid
print paid_date
# et cetera...
You could create:
the_dict = dict(amount_paid=ap, paid_date=pd, method=method, comments=comments)
Also your template code does not make sense. You are iterating over the keys of the dict and not using them in the body.
EDIT
{% for key in the_dict %}
{% for val in the_dict[key] %}
<input name="{{key}}" value="{{val}}"/>
{% endfor %}
{% endfor %}
As often happens, you're not really asking about the problem you actually need to solve: you've done things in a certain (wrong) way, and are asking about how to get yourself out of the problem you've got yourself into.
If I understand you correctly, you've got a set of fields - amount_paid, paid_date, method, comments - and each field appears multiple times on the form, so you've got one set of values for each entry. You're presumably trying to sort these into a list of dicts for each row.
Well, this is not the right way to go about it in Django. You should be using formsets, which give you one form for each row in a table - ie, exactly what you want to achieve.