python flask app, using dictionary with variables - python

So I'm trying to reach dictionary parameters with a variable but looks like you can't use it with the traditional way (mydict[var])
I'm passing a dictionary and a list to HTML:
#app.route('/')
def setup():
jinda = {
'first':'1234'
'second':'4567'
'third': '7890'
}
zirna = ['first', 'third']
return render_template('table.html', zirna=zirna, jinda=jinda)
Now in HTML I want to use a for loop two reach specific elements in the dictionary which is also in the list but I don't know how to do that also this one is not working ๐Ÿ‘‡:
{% for i in zirna %}
<p> {{ jinda[i] }}<p>
{% endfor %}

This works for me and outputs:
<p> 1234<p>
<p> 7890<p>
However there is a syntax error in your python code. Commas should be used between each key:value when defining the dictionary:
jinda = {
'first':'1234',
'second':'4567',
'third': '7890',
}
Perhaps this is your issue, although I would expect this to throw a syntax error when launching your app.

Related

I simply can't change python unicode

I'm working with flask and sqlalchemy to print a list in an html page. Code is below
Python code:
#app.route('/restaurants')
def showRestaurants():
restaurant = session.query(Restaurant.name)
return render_template('restaurants.html', restaurant = restaurant)
Html code:
<ul>
{% for i in range(0,9) %}
<li>
<strong>{% print(restaurant[i]) %}</strong>
</li>
{% endfor %}
</ul>
Page:
(u'Urban Burger',)
(u'Super Stir Fry',)
(u'Panda Garden',)
(u'Thyme for That Vegetarian Cuisine ',)
(u"Tony's Bistro ",)
(u"Andala's",)
(u"Auntie Ann's Diner ",)
(u'Cocina Y Amor ',)
(u'State Bird Provisions',)
So, what am I doing wrong? I have a database with restaurant names and wanna make a list of it but it seems impossible to decode it. I've already tried .encode() which print out an error says the variable encode is not define and when I put in create_engine encoding = 'acsii' simply does nothing. I appreciate any help.
SQLAlchemy's session.query returns a list of tuples. So, to display the name of each restaurant, you'd want to access the string in the first element of each tuple.
<strong>{% print(restaurant[i][0]) %}</strong>
encode('ascii') will work, but you have to apply it to the unicode string. The problem you have right now is that you are printing out a tuple not a string.
Instead, try referencing the restaurants like this:
restaurant[i][0].encode('ascii')
Even restaurant[i][0] might render correctly.

Jinja2: format + join the items of a list

play_hosts is a list of all machines for a play. I want to take these and use something like format() to rewrite them like rabbitmq#%s and then join them together with something like join(). So:
{{ play_hosts|format(???)|join(', ') }}
All the examples of format use piping where the input is the format string and not a list. Is there a way to use these (or something else) to accomplish what I want? The output should looks something like:
['rabbitmq#server1', 'rabbitmq#server2', rabbitmq#server3', ...]
The jinja2 doc describes format like this:
format(value, *args, **kwargs)
Apply python string formatting on an object:
{{ "%s - %s"|format("Hello?", "Foo!") }}
-> Hello? - Foo!
So it gives three kinds of input but doesn't describe those inputs in the example, which shows one in the pipe and the other two passed in via args. Is there a keyword arg to specify the string that's piped? Please help, python monks!
In ansible you can use regex_replace filter:
{{ play_hosts | map('regex_replace', '^(.*)$', 'rabbitmq#\\1') | list }}
I believe another way would be using the joiner global function, as you can read in http://jinja.pocoo.org/docs/2.9/templates/#list-of-global-functions:
A joiner is passed a string and will return that string every time itโ€™s called, except the first time (in which case it returns an empty string). You can use this to join things
So your code would be something like:
[
{% set comma = joiner(",") %}
{% for host in play_hosts %}
{{ comma() }}
{{ "rabbitmq#%s"|format(host) }}
{% endfor %}
]
You can create custom filter
# /usr/share/ansible/plugins/filter/format_list.py (check filter_plugins path in ansible.cfg)
def format_list(list_, pattern):
return [pattern % s for s in list_]
class FilterModule(object):
def filters(self):
return {
'format_list': format_list,
}
and use it
{{ play_hosts | format_list('rabbitmq#%s') }}
You could simply join not only by , but also add the prefix together with it. Now that's not very pythonic or sophisticated but a very simple working solution:
[rabbitmq#{{ play_hosts | join(', rabbitmq#') }}]
If you want to format a string, through a list.
l: list = ["world", "stackoverflow"]
"Hello %s and %s"|format(*l)

Extending Jinja's {% trans %} to use JavaScript variables

I'd like to extend the behaviour of trans by rendering variables not as as values from the context, but instead as html (without using the context). My aim is to be able to populate those variables on the client through JavaScript.
Jinja as it seems doesn't allow for a great deal of customisation of this kind or I'm just unable to find the right hooks.
Here's what I'd like to achieve:
{% etrans name=username %}
My name is {{ name }}
{% endetrans %}
This should render to:
My name is <span id='#username'></span>
Of course, I could just use the normal {% trans %} directive and pass my html code to template.render(html_code_params), but that would require to have them defined in the template and the rendering code which I'd like to avoid.
Here's what I got so far (not much) which allows for a new etrans tag and the ability to use whatever goodies InternationalizationExtension has to offer.
from jinja2.ext import InternationalizationExtension
from jinja2.runtime import concat
class JavaScriptVariableExtension(InternationalizationExtension):
tagname = 'etrans'
tags = set([tagname])
def _parse_block(self, parser, allow_pluralize):
"""Parse until the next block tag with a given name.
Copy from InternationalizationExtension, as this uses hardcoded
`name:endtrans` instead of relying on tag name
"""
referenced = []
buf = []
while 1:
if parser.stream.current.type == 'data':
buf.append(parser.stream.current.value.replace('%', '%%'))
next(parser.stream)
elif parser.stream.current.type == 'variable_begin':
next(parser.stream)
name = parser.stream.expect('name').value
referenced.append(name)
buf.append('%%(%s)s' % name)
parser.stream.expect('variable_end')
elif parser.stream.current.type == 'block_begin':
next(parser.stream)
# can't use hardcoded "endtrans"
# if parser.stream.current.test('name:endtrans'):
if parser.stream.current.test('name:end%s' % self.tagname):
break
elif parser.stream.current.test('name:pluralize'):
if allow_pluralize:
break
parser.fail('a translatable section can have only one '
'pluralize section')
parser.fail('control structures in translatable sections are '
'not allowed')
elif parser.stream.eos:
parser.fail('unclosed translation block')
else:
assert False, 'internal parser error'
return referenced, concat(buf)
i18n_extended = JavaScriptVariableExtension
I don't mind overloading more methods (although the reason for above one should perhaps fixed upstream).
Stepping through the code is quite an interesting adventure. However, I hit a snag and am interested if anyone can give some advice.
The problem I see is that during the compilation, the function context.resolve() gets baked into the compiled code. jinja2.jinja2.compiler.CodeGenerator doesn't really allow any different handling here (correct me if I'm wrong). Ideally, I would define another node (for the variable) and this node would handle the way it's dealt with during compilation, but I don't see how this is possible. I might be too focussed on this as a solution, so perhaps someone can provide alternatives.
As suggested by #Garrett's comment, a much easier solution is to pass in a function to the template renderer that interpolates the variables. In my case, my target client-side framework is Angular, but this also works for any JS variables that you want to use within a {% trans %} environment. Here are the building blocks:
def text_to_javascript(string):
# modify as needed...
return "<span>{{ %s }}</span>" % string
def render():
tmpl = jinja_env.get_template(template_filename)
return tmpl.render({'js': text_to_javascript})
And this how I make use of it in the template file:
{% trans username=js('user.name') %}
My name is {{ username }}
{% endtrans %}
In the Angular controller, the variable user is bound to the $scope like so:
$scope.user = {'name': 'Bugs Bunny'}

How to remove select characters from xml parse in python / django?

Context
I am working on a django project and I need to loop through a nested dictionary to print the values
Here's the dictionary:
{body{u'#copyright': u'All data copyright Unitrans ASUCD/City of Davis 2015.', u'predictions': {u'#routeTitle': u'A', u'#dirTitleBecauseNoPredictions': u'Outbound to El Cemonte', u'#agencyTitle': u'Unitrans ASUCD/City of Davis', u'#stopTag': u'22258', u'#stopTitle': u'Silo Terminal & Haring Hall (WB)', u'#routeTag': u'A', u'message': [{u'#text': u'Weekend service is running Monday-Wednesday Dec. 28-30.', u'#priority': u'Normal'}, {u'#text': u'The A-line and Z-line do not run on weekends. Use O-line for weekend service.', u'#priority': u'Normal'}]}}}
I am parsing the dictionary from the following url:
http://webservices.nextbus.com/service/publicXMLFeed?command=predictions&a=unitrans&r=A&s=22258
Problem 1
I am getting trouble displaying the values of keys with '#' in them using django template tags, for example
{% for i in data%}
{% i.#copyright %}
{% endfor %}
This gives an error saying could not parse remainder.
Problem 2
One of the values has a nested dictionary in it with square brackets
[{u'#text': u'Weekend service is running Monday-Wednesday Dec. 28-30.', u'#priority': u'Normal'}, {u'#text': u'The A-line and Z-line do not run on weekends. Use O-line for weekend service.', u'#priority': u'Normal'}]
I cannot loop through this using for loop template tags
The solution I have in mind
In order to solve this and make it simpler I am looking to strip the characters '#', '[' and ']'from the xml, this would leave me with a much simpler dictionary which would be easy to loop through.
My Python Code Right Now in views.py
import xmltodict
import requests
def prediction(request, line, s_id):
url = "http://webservices.nextbus.com/service/publicXMLFeed? command=predictions&a=unitrans&r=" + line + "&s=" + s_id
data = requests.get(url)
data = xmltodict.parse(data, dict_constructor=dict)
data_dict = {}
data_dict["data"] = data
return render(request, 'routes/predictions.html', data_dict)
What I want to display on page predictions.html
Route Tag: A
Message : Weekend Service is running Monday-Wednesday Dec. 28-30.
The A-Line and Z-Line do not run on weekends. use O-Line for weekend service.
Priority: Normal
I would appreciate any inputs on this problem. Thank you for your time.
In xmltodict, the '#' symbols are there to indicate attributes of xml nodes, and the '[' and ']' are used to delimit element values that are themselves a list of values. (Here, it indicates the 'message' value is itself a list of two message objects). You can certainly try to read in the dict as raw text and scrape out what you need, but that won't take advantage of the reason most people are importing it to begin with: To organize the data and make it easier to access.
Instead of scraping the text, you can easily craft a template that would just pull the specific values from the dict that you want. Your data dict should be structured something like this:
{
body:
{
u'#copyright': u'All data copyright Unitrans ASUCD/City of Davis 2015.',
u'predictions':
{
u'#routeTitle': u'A',
u'#dirTitleBecauseNoPredictions': u'Outbound to El Cemonte',
u'#agencyTitle': u'Unitrans ASUCD/City of Davis',
u'#stopTag': u'22258',
u'#stopTitle': u'Silo Terminal & Haring Hall (WB)',
u'#routeTag': u'A',
u'message':
[
{
u'#text': u'Weekend service is running Monday-Wednesday Dec. 28-30.',
u'#priority': u'Normal'
},
{
u'#text': u'The A-line and Z-line do not run on weekends. Use O-line for weekend service.',
u'#priority': u'Normal'
}
]
}
}
}
To get the output you want, create a template tailored for this data and then just insert directly the values you need. Something like this: (apologies, I don't know django template syntax exactly)
Route Tag: {{ data_dict.body.predictions.routeTitle }}
Messages :
<ul>
{% for msg in data_dict.body.predictions.message %}
<li>{{ msg.text }} (Priority: {{ msg.priority }})</li>
{% endfor %}
</ul>

Parsing/extracting from OrderedDict using Jinja in Salt

I am running into a rather weird issue while parsing results of a salt command. The command I am running is
{% set hostname = salt['publish.publish']('roles:*{}*'.format(role), 'grains.item', 'fqdn', 'grain') %}
And output looks below:
OrderedDict([('1.server.com', OrderedDict([('fqdn', '1.server.com')])), ('0.server.com', OrderedDict([('fqdn', '0.server.com')]))])
Now my understanding is when I do items() on above result with a line below, it should work
{% for hostname, fqdn in salt['publish.publish']('roles:*{}*'.format(role), 'grains.item', 'fqdn', 'grain').items() %}
But the moment I use items() in above line I start running into an error:
failed: Jinja variable 'None' has no attribute 'items'
I tried a couple of other ways (Doing items().items() or storing result in a variable and then running for loop over) to get the list out of OrderedDict but none of ways seem to help.
Either I don't know Python enough or there is something weird going on. Simply adding a check has made the above work. So working block looks like (Partial code of course):
{% set hostname = salt['publish.publish']('roles:*{}*'.format(role), 'grains.item', 'fqdn', 'grain') %}
{% if hostname is not none %}
{% for host, site in hostname.items() %}
My understanding is if check was only meant for checking just in case hostname is empty. But looks like even if there is data - an if check is needed. Still curious to know the mystery!

Categories