Flask Webpage Via Cron Job – url_for call broken
Question:
I have a Script that lives in my Flask App that executes every 5 minutes. For many reasons. But that doesn’t matter.
When I run this code I am now wanting to include links in this webpage to functions in my app.py Flask app.
app.py:
@app.route('/Historical-Service-Transitions/<service>')
@login_required
@nocache
def HSPC(service):
return service
kickoff.py which runs on a schedule.
from jinja2 import Template
import paramiko
import socket
import time
import pprint
import sys
import mysql.connector
from mysql.connector import errorcode
from collections import namedtuple
import datetime
from app import HSPC
from flask import url_for
source_html =Template(u'''
....#The part that is failing
<tbody>
{% for x in the_best %}
<tr>
<td><a href="{{ url_for('HSPC', service ='x.service') }}">{{x.service}}</a></td>
<td>{{x.ip}}</td>
<td>{{x.router}}</td>
<td>{{x.detail}}</td>
<td>{{x.time}}</td>
</tr>
{% endfor %}
</tbody>
....''')
full_html = source_html.render(
the_best=the_best,
the_time=the_time
)
write_that_sheet = open("/var/www/flask-intro/templates/Test.html", "w+")
write_that_sheet.write(full_html)
write_that_sheet.close()
Error:
Traceback (most recent call last):
File "kickoff.py", line 1199, in <module>
the_time=the_time
File "/usr/lib/python2.6/site-packages/Jinja2-2.7.3-py2.6.egg/jinja2/environment.py", line 969, in render
return self.environment.handle_exception(exc_info, True)
File "/usr/lib/python2.6/site-packages/Jinja2-2.7.3-py2.6.egg/jinja2/environment.py", line 742, in handle_exception
reraise(exc_type, exc_value, tb)
File "<template>", line 534, in top-level template code
jinja2.exceptions.UndefinedError: 'url_for' is undefined
Any Help would be much appreciated.
Update:
I am unable to find anything even remotely close to what I am attempting to do. I understand that I can rebuild this so that way the background Python code grabs the info and my app.py
builds the HTML. A background application would populate a database, and then a function within the app.py
would grab the info needed from the database and post to the HTML Page.
While this is very much last resort as it requires me to redesign this entire part of the application I still would like to see if there is a solution that would allow me to generate a this webpage outside of the app.py
Flask.
Answers:
You are missing the Jinja context that Flask provides. Use flask.render_template_string()
to render a template defined in a string and the right template context will be provided for you:
from flask import render_template_string
source_html = u'''
<tbody>
{% for x in the_best %}
<tr>
<td><a href="{{ url_for('HSPC', service ='x.service') }}">{{x.service}}</a></td>
<td>{{x.ip}}</td>
<td>{{x.router}}</td>
<td>{{x.detail}}</td>
<td>{{x.time}}</td>
</tr>
{% endfor %}
</tbody>
'''
filename = "/var/www/flask-intro/templates/Test.html"
# provide a fake request context for the template
with app.test_request_context('/'), open(filename, "w") as outfh:
full_html = render_template_string(
source_html, the_best=the_best, the_time=the_time)
outfh.write(full_html)
However, for a periodic job, you could just use curl
to call a special URL in your Flask app to have it write template output to a file.
I have a Script that lives in my Flask App that executes every 5 minutes. For many reasons. But that doesn’t matter.
When I run this code I am now wanting to include links in this webpage to functions in my app.py Flask app.
app.py:
@app.route('/Historical-Service-Transitions/<service>')
@login_required
@nocache
def HSPC(service):
return service
kickoff.py which runs on a schedule.
from jinja2 import Template
import paramiko
import socket
import time
import pprint
import sys
import mysql.connector
from mysql.connector import errorcode
from collections import namedtuple
import datetime
from app import HSPC
from flask import url_for
source_html =Template(u'''
....#The part that is failing
<tbody>
{% for x in the_best %}
<tr>
<td><a href="{{ url_for('HSPC', service ='x.service') }}">{{x.service}}</a></td>
<td>{{x.ip}}</td>
<td>{{x.router}}</td>
<td>{{x.detail}}</td>
<td>{{x.time}}</td>
</tr>
{% endfor %}
</tbody>
....''')
full_html = source_html.render(
the_best=the_best,
the_time=the_time
)
write_that_sheet = open("/var/www/flask-intro/templates/Test.html", "w+")
write_that_sheet.write(full_html)
write_that_sheet.close()
Error:
Traceback (most recent call last):
File "kickoff.py", line 1199, in <module>
the_time=the_time
File "/usr/lib/python2.6/site-packages/Jinja2-2.7.3-py2.6.egg/jinja2/environment.py", line 969, in render
return self.environment.handle_exception(exc_info, True)
File "/usr/lib/python2.6/site-packages/Jinja2-2.7.3-py2.6.egg/jinja2/environment.py", line 742, in handle_exception
reraise(exc_type, exc_value, tb)
File "<template>", line 534, in top-level template code
jinja2.exceptions.UndefinedError: 'url_for' is undefined
Any Help would be much appreciated.
Update:
I am unable to find anything even remotely close to what I am attempting to do. I understand that I can rebuild this so that way the background Python code grabs the info and my app.py
builds the HTML. A background application would populate a database, and then a function within the app.py
would grab the info needed from the database and post to the HTML Page.
While this is very much last resort as it requires me to redesign this entire part of the application I still would like to see if there is a solution that would allow me to generate a this webpage outside of the app.py
Flask.
You are missing the Jinja context that Flask provides. Use flask.render_template_string()
to render a template defined in a string and the right template context will be provided for you:
from flask import render_template_string
source_html = u'''
<tbody>
{% for x in the_best %}
<tr>
<td><a href="{{ url_for('HSPC', service ='x.service') }}">{{x.service}}</a></td>
<td>{{x.ip}}</td>
<td>{{x.router}}</td>
<td>{{x.detail}}</td>
<td>{{x.time}}</td>
</tr>
{% endfor %}
</tbody>
'''
filename = "/var/www/flask-intro/templates/Test.html"
# provide a fake request context for the template
with app.test_request_context('/'), open(filename, "w") as outfh:
full_html = render_template_string(
source_html, the_best=the_best, the_time=the_time)
outfh.write(full_html)
However, for a periodic job, you could just use curl
to call a special URL in your Flask app to have it write template output to a file.