Cameron Kilgore
Cameron Kilgore

Reputation: 423

UndefinedError: 'url_for_other_page' is undefined

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 &raquo;</a>
      {% endif %}
      </div>
</div>

Upvotes: 1

Views: 733

Answers (1)

Anand S Kumar
Anand S Kumar

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

Related Questions