Reputation: 423
I am encountering a (probably) rookie mistake from inherited code within Flask. A helper function inside my template, url_for_other_page()
is not being initialized when the page in question loads. Returns a self-descriptive error:
UndefinedError: 'url_for_other_page' is undefined
I know what's causing this -- the helper method is not getting polled because it's not exposed to the url in question, or something. What's the best approach to this without exposing more than is necessary to the URL path in question? Should the helper function be elsewhere in the application logic (such as in init?)
Below is the template snippet that causes the offending error, and the entire core.py, where the application logic lives. Requests are made to /images, which returns the results of entries_index()
to the template call. This pagination code is pretty much co-opted from Flask's own examples. The full source can be viewed on Github if you need additional context.
core.py
import hashlib, os
from flask import request, session, render_template, flash, url_for, \
redirect, send_from_directory
from werkzeug import secure_filename
from kremlin import app, db, dbmodel, forms, imgutils, uploaded_images
from pagination import Pagination
@app.route('/')
def home_index():
""" Display the glasnost logo, attempt to replicate old behavior """
return render_template('home.html')
@app.route('/images', defaults={'page': 1})
@app.route('/images/page/<int:page>')
def entries_index(page):
""" Show an index of image thumbnails """
posts = dbmodel.Post.query.all()
pagination = Pagination(page, 2, len(posts))
#import pdb; pdb.set_trace()
return render_template('board.html', form=forms.NewPostForm(),
posts=posts, pagination=pagination)
# The offending helper method
def url_for_other_page(page):
args = request.view_args.copy()
args['page'] = page
return url_for(request.endpoint, **args)
app.jinja_env.globals['url_for_other_page'] = url_for_other_page
@app.route('/images/<int:post_id>')
def view_post(post_id):
""" Show post identified by post_id """
post = dbmodel.Post.query.get_or_404(post_id)
comments = dbmodel.Comment.query.filter_by(parent_post_id=post_id)
return render_template('post.html', post=post, comments=comments)
@app.route('/images/get/<filename>')
def send_file(filename):
"""Send image file to browser"""
return send_from_directory(app.config['UPLOADED_IMAGES_DEST'],
filename)
@app.route('/images/add/', methods=['POST'])
def add_image():
""" Add a new image """
form = forms.NewPostForm()
if form.validate_on_submit():
filename = secure_filename(form.upload.file.filename)
fileext = os.path.splitext(filename)[1]
filedata = form.upload.file.stream.read()
# Calculate SHA1 checksum
h = hashlib.new('sha1')
h.update(filedata)
filehash = h.hexdigest()
# Validate file uniqueness
dupe = dbmodel.Image.query.filter_by(sha1sum=filehash).first()
if dupe:
flash("Image already exists: %s" % (dupe))
return redirect(url_for('entries_index'))
else:
# File is unique, proceed to create post and image.
# Save file to filesystem
# Rewind file, it was read() by the SHA1 checksum
# routine
form.upload.file.seek(0)
# Proceed with storage
try:
uploaded_images.save(storage=form.upload.file,
name=''.join([filehash, '.']),
)
# FIXME: generate thumbnail in a safer way.
# This is fairly horrible and I'm sorry.
imagepath = uploaded_images.path(''.join([filehash, fileext]))
imgutils.mkthumb(imagepath)
except IOError:
flash("Oh god a terrible error occured while saving %s" %
(filename))
else:
dbimage = dbmodel.Image(filename, filehash)
db.session.add(dbimage)
user = None
if "uid" in session:
user = dbmodel.User.query.filter_by(
id=session['uid']
).first()
note = form.note.data
#TODO: Implement tags.
# Create a new post with the image
post = dbmodel.Post(image=dbimage, title=filename,\
note=note, user=user)
db.session.add(post)
# Commit database transaction
db.session.commit()
flash("Image successfully posted!")
return redirect(url_for('entries_index'))
else:
flash("Your form has terrible errors in it.")
return(redirect(url_for("entries_index")))
template call (excerpt from board.html)
<div id='ImageboardPageTop'>
<div class=pagination>
{% for page in pagination.iter_pages() %}
{% if page %}
{% if page != pagination.page %}
<a href="{{ url_for_other_page(page) }}">{{ page }}</a>
{% else %}
<strong>{{ page }}</strong>
{% endif %}
{% else %}
<span class=ellipsis>…</span>
{% endif %}
{% endfor %}
{% if pagination.has_next %}
<a href="{{ url_for_other_page(pagination.page + 1)
}}">Next »</a>
{% endif %}
</div>
</div>
Upvotes: 1
Views: 733
Reputation: 90929
This line needs to go into your core.py , not inside the function - url_for_other_page
-
app.jinja_env.globals['url_for_other_page'] = url_for_other_page
Code -
def url_for_other_page(page):
args = request.view_args.copy()
args['page'] = page
return url_for(request.endpoint, **args)
app.jinja_env.globals['url_for_other_page'] = url_for_other_page
Upvotes: 1