Pass Two Values in For Loop Python - python

I have two Python files and one HTML file. One of the Python files is using Flask to connect with the HTML file.
In file1.py(the non Flask one) I set a for loop to print the variable volume
for volume in current_volumes:
print volume
which prints out two strings in Terminal
Volume:vol-XXXXXXX
Volume:vol-YYYYYYY
Now I put from file1 import * on the top of file2.py.
Additionally, file2.py contains
def template(name=volume):
return render_template('index.html', name=name)
Index.html contains
<p>{{ name }}</p>
but only reads Volume:vol-YYYYYYY when launched.
How do I get it to print out both values of volume?

I think you want to use a for loop to create a new string:
volume_string = ""
for volume in current_volumes:
volume_string += volume
def template(name=volume_string):
...
You can insert a "\n" (newline) at the end of every volume appended to get it to 2 print lines.
I haven't played around with Flask, but you may also want to just try
def template(name=current_volumes):
Perhaps it's smart enough to make that work.

You are using an escaping for variable volume rather than the list of volumes (current_volumes). (Should you switch to Python 3 this will raise a ReferenceError instead of working). Change:
def template(name=volume):
return render_template('index.html', name=name)
to:
def template(name=current_volumes):
return render_template('index.html', name=name)
You will also want to change your {{ name }} to a loop - let's go ahead and change the name:
def template(volumes=current_volumes):
return render_template('index.html', volumes=volumes)
and then add a loop in our Jinja template:
{% for volume in volumes %}
<p>Volume Data: {{ volume }}</p>
{% endfor %}

Related

calling python function within saltstack sls

I am new in saltstack and i have some troubles creating a python function to make some regex checks.
i have this function
from re import sub, match, search
def app_instance_match(app):
instance_no = 0
m = search('^(.*)(-)(\d)$', app)
if m is not None:
app = m.group(1)
instance_no = int(m.group(3))
return app, instance_no
when i call it from console with
salt-ssh -i 'genesis-app-1' emod.app_instance_match test-14
i get
$ salt-ssh -i 'genesis-app-1' emod.app_instance_match test-14
genesis-app-1:
- test-14
- 0
When i try to use it inside a sls file like
{% set app = salt['emod.app_instance_match'](app) %}
i cannot use the app anymore. i tried
{% for x,y in app %}
test:
cmd.run:
- names:
- echo {{x} {{y}}
or like
cmd.run:
- names:
- echo {{app}}
I know that it return to me a dictionary but i am unable to access the values of it. The only thing that i need is the 2 returns from the python function: test-14 and 0.
when i echo for testing the X from the loop fox x,y in app i saw values like retcode, stdout, stderror.
Is there any other way to syntax the
{% set app = salt['emod.app_instance_match'](app) %}
something like that so will have 2 set variables in sls
{% set app,no = salt['emod.app_instance_match'](app) %}
i also tried like
{% set app = salt['emod.app_instance_match'](app).items() %}
I am missing something in the syntax but i cannot find anything in the internet to help me continue. I have the values that i want inside app, but i am not able to access them to take the part that i want.
First, You are not getting a dict back, you are getting a tuple back. there is a big difference. second {% set app,no = salt['emod.app_instance_match'](app) %} is exactly what you should be using. that will split the variables into two parts app and no. I should note sometimes using salt-ssh actually makes debugging things in salt harder. I would suggest installing a local minion to at least test these basic things.
Here is an example using your own code. I named it epp instead of emod.
[root#salt00 tests]# cat tests.sls
{% set x,y = salt['epp.app_instance_match']('test-14') %}
x: {{x}}
y: {{y}}
[root#salt00 tests]# salt-call slsutil.renderer salt://tests/tests.sls default_render=jinja
local:
----------
x:
test-14
y:
0
[root#salt00 tests]# cat ../_modules/epp.py
from re import sub, match, search
def app_instance_match(app):
instance_no = 0
m = search('^(.*)(-)(\d)$', app)
if m is not None:
app = m.group(1)
instance_no = int(m.group(3))
return app, instance_no
The second thing is you might want to look at https://docs.saltproject.io/en/latest/topics/jinja/index.html#regex-search which is already a regex search.
And third. Your regex looks off. ^ and $ don't really work well with single strings. which would explain why test-14 didn't come back as ('test',1) but instead came back as ('test-14',0)
I'm thinking you want '(.*)-(\d*)' as your real regex. which will return ('test',14) for test-14

Jinja 2 - displaying all my words instead of one

Please excuse my code, I am still a relative beginner trying to complete a school project! Basically, I am trying to create a language learning system where you input a word and it checks if it is correct. However, on the page learn.html all of the words in my database are coming up. I want to get it so that when you load the page there is the first word and when you click the button it checks that word, allowing the page to display the next word to translate. An example of this would be memrise, this screenshot shows the kind of system that I am trying to emulate.
I know that this is because of the for loop but I have tried lots of solutions to no success. It seems like a really easy problem but I am really stuck. I have 0 JavaScript expertise so if possible I would try to stay away from JS solutions. I will really appreciate any help possible :)
learn.html
{% block content %}
<form class = "form" id="form1" action="/learn/check" methods=["POST"]>
<td>
<h5> Please enter the spanish for : {% for word in course_content %}{{ word.english }} {% endfor %} </h5>
<input type="text" name="language_learning_input" id="desc" value="" size="100" maxlength="140"/>
<p> </p>
</td>
<input type="submit" name="button" class="btn btn-success" value="Update"/>
</form>
{% endblock content %}
snippet of main.py
#LEARN SYSTEM
#STORING DB VALUES IN LISTS
def spanish():
#setting variables
holding_spanish = []
#running db query
course_content = db.session.query(Course).all()
#iterating through db
for row in course_content:
holding_spanish.append(row.spanish)
return holding_spanish
def english():
#setting variables
holding_english = []
#running db query
course_content = db.session.query(Course).all()
#iterating through db
for row in course_content:
holding_english.append(row.english)
return holding_english
def score():
#setting variables
holding_score = []
#running db query
account_settings = db.session.query(AccountSettings).all()
#iterating through db
for row in account_settings:
holding_score.append(row.words_per_lesson)
return holding_score
#MAIN LEARN PAGE
#app.route("/learn")
def learn():
#getting values
english()
spanish()
score()
x=1
testingvalue = [score()]
acccount_settings = db.session.query(AccountSettings).all()
course_content = db.session.query(Course).all()
return render_template('learn.html', course_content=course_content, acccount_settings=acccount_settings,testingvalue=testingvalue,x=x,english=english)
#ROUTE USED TO CHECK
#app.route("/learn/check", methods =['GET'])
def learncheck():
course_content = db.session.query(Course).all()
language_learning_input = request.args.get('language_learning_input')
for row in course_content:
if language_learning_input == row.spanish:
"<h1> correcto! </h1>"
print("true")
else:
"<h1> not correcto! :</h1>"
print("false")
Basically you need to understand two things.
First, of the many words you have to return only one. *
So, how do you know which word the user has already seen?
You don't. HTTP is a stateless protocoll. That means, each request (access by a browser) is independent of another one.
But you can work around this limitation.
So, second, you need to save the state. And there are several concepts.
From the top of my head, you could use
sessions
cookies
or pass a parameter with e.h. the current word, so you can deduct the next word
That's it. Enjoy your homework and do not hesitate to create a new question when you encounter a specific problem
You could also return all words, and then do the cycling through the words via Javascript.

Flask correct variable value on terminal but not in HTML template

Similar question which does not solve my problem.
I have a Flask app which reads from a database and renders an HTML template using the DB data. I'm trying to manipulate a value I get from the DB before sending it to the HTML template and this doesn't work.
Python code:
#app.route('/pilot', methods=['GET'])
def form_view():
result = {}
# query DB and get cursor
numQuestions = 0
for row in cursor:
row.pop('_id', None) # delete the key and add modified key back
row['_id'] = row['stage'][-1] # get only last char- eg, "1" from "stage1", "2" from "stage2" and so on
print(row['_id'])
result[numQuestions] = row
numQuestions += 1
return render_template("form.html", count=numQuestions, result=result, debug=app.debug)
Output when run on terminal is as expected:
1
1
1
2
2
2
Jinja2 fragment of form.html:
{% for row in result[row_num]['scrutiny_stage'] %}
{{ row['_id'] }}
{% endfor %}
Output on browser:
stage1 stage1 stage1 stage2 stage2 stage2 stage2
Can anyone help me understand what I'm doing wrong here and how I can get the correct value of the variable I'm setting in the Python code to show up in the HTML template being rendered by Flask?
Thanks.
Thanks for the tips folks, even though I couldn't share all the context (since I have to protect proprietary info), they were helpful. I managed to solve this with multiple steps:
I redid my DB schema so that every document has an '_id' key with a plain numeric value. I dropped the 'stage': 'stage1' kinds of fields. The 'stage' is now computed dynamically in the code base on the DB query results.
Then I changed the Flask view function to add a 'stage' key to the result dict being passed to the HTML template (no mucking around with the '_id' field):
numQuestions = 0
for row in cursor:
for line in row['scrutiny_stage']:
row['stage'] = line['_id']
result[numQuestions] = row
numQuestions += 1
Finally, in my Jinja2 block, I realized that I need to operate over the result as a dict, so I changed it to use the dict.values() method:
{% for row in result.values() %}
{{ row['stage'] }}
{% endfor %}
Now, I get the same values printed in the terminal as well as in my browser.

jinja2 include file with variable

I'm trying to refacto some pretty heavy template with jinja2 and I'm stucked on an include.
This is the behaviour i'm expecting :
<h1>{{ key }} </h1>
{% set file = key | include_text %}
{% include file %}
The custom filter returns a string like this one ::
texts/my_include.html
But instead I got this error:
jinja2.exceptions.TemplatesNotFound: Tried to select from an empty list of templates
Some hack I've already tried :
Place the templates in the same folder and remove the 'texts/' from the returned string
Add the path in the Env loader
But it keeps sending this error
I'm now wondering if jinja2 allows this implementation or if I'll have to keep this template the way it was (even if it takes a very long time to be generated).
Does someone know about some trick here ?
Well, for those who eventually met this problem in the futur, I've solved it by removing the unecessary single quotes and by sending some empty file from my custom filter when the condition is not verified... (my mistake)
Here is my custom filter :
#environmentfilter
def include_text(ctx, key):
res_dict = {
'key_value_1' : 'file_name_1',
'key_value_2' : 'file_name_2'
}
try:
return "texts/" + res_dict[key] + ".html"
except KeyError:
return "texts/empty.html"
Now, the first solution I was trying works fine.

How do I use Jinja2 filter on a block with argumets

I am trying to use jinja2 templates. I have custom filter called highlight, that takes string and language name and passes them to pyhments for code highlightning. I am trying to use it like this:
{% filter highlight("python") %}
import sys
def main():
pass
{% endfilter %}
But I get this error:
AttributeError: 'str' object has no attribute 'get_tokens'
Then I tried this:
{% filter highlight "python" %}
It does not work either.
There might be a trick via set block filtering and then pasting it back via {{ ... }}, but this technique is not merged in master source code yet, and seems too hacky for me.
So, is that even possible currently, or I am just doing it wrong?
EDIT: Here is filter:
#jinja2.contextfilter
def highlight(context, code, lang):
print("HIGHLIGHT")
print(code)
return jinja2.Markup(pygments.highlight(code, lexer=lang, formatter='html'))
I am an idiot, that was pygments error. By some mistake, I didn't see that last entry in stacktrace was from there.
You should use:
pygments.highlight(
code,
lexer=pygments.lexers.get_lexer_by_name(lang),
formatter=pygments.formatters.get_formatter_by_name('html')
)
instead of:
pygments.highlight(code, lexer=lang, formatter='html')

Categories

Resources