Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering template gives "jinja2.exceptions.UndefinedError: 'form' is undefined"

I am working through Miguel Grinberg's Flask Mega Tutorial and I cannot figure out why the index page now fails to load. Here is the traceback:

  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask_login.py", line 658, in decorated_view
    return func(*args, **kwargs)
  File "/home/asdoylejr/microblog/app/views.py", line 44, in index
    posts = posts)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/templating.py", line 128, in render_template
    context, ctx.app)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/flask/templating.py", line 110, in _render
    rv = template.render(context)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/jinja2/environment.py", line 969, in render
    return self.environment.handle_exception(exc_info, True)
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/jinja2/environment.py", line 742, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/home/asdoylejr/microblog/app/templates/index.html", line 2, in top-level template code
    {% extends "base.html" %}
  File "/home/asdoylejr/microblog/app/templates/base.html", line 30, in top-level template code
    {% block content %}{% endblock %}
  File "/home/asdoylejr/microblog/app/templates/index.html", line 7, in block "content"
    {{form.hidden_tag()}}
  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/jinja2/environment.py", line 397, in getattr
    return getattr(obj, attribute)
UndefinedError: 'form' is undefined

Here is the code for the index page in question:

<!-- extend base layout -->
{% extends "base.html" %}

{% block content %}
<h1>Hi, {{g.user.nickname}}!</h1>
<form action="" method="post" name="post">
    {{form.hidden_tag()}}
<table>
    <tr>
        <td>Say something:</td>
        <td>{{form.post(size = 30, maxlength = 140)}}</td>
        <td>
        {% for error in form.errors.post %}
        <span style="color: red;">[{{error}}]</span><br>
        {% endfor %}
        </td>
    </tr>
    <tr>
        <td></td>
        <td><input type="submit" value="Post!"></td>
        <td></td>
    </tr>
</table>
</form>
{% for post in posts %}
<p>
    {{post.author.nickname}} says: <b>{{post.body}}</b>
</p>
{% endfor %}
{% endblock %}

And here is the code in the view:

@app.route('/', methods = ['GET', 'POST'])
@app.route('/index', methods = ['GET', 'POST'])
@login_required
def index():
    form = PostForm()
    if form.validate_on_submit():
        post = Post(body = form.post.data, timestamp = datetime.utcnow(), author = g.user)
        db.session.add(post)
        db.session.commit()
        flash('Your post is now live!')
        return redirect(url_for('index'))
    posts = g.user.followed_posts().all()
    return render_template("index.html",
        title = 'Home',
        user = user,
        posts = posts)

I've read through the tutorial multiple times, and compared my code to the source at the end of each lesson, and I have no idea why it is not working. I'm not sure why it's having trouble passing form in this view when it does not return an error passing forms in another view.

Can anyone point me in the right direction?

like image 834
asdoylejr Avatar asked Oct 21 '13 22:10

asdoylejr


People also ask

What is Jinja template used for?

It is a text-based template language and thus can be used to generate any markup as well as source code. The Jinja template engine allows customization of tags, filters, tests, and globals. Also, unlike the Django template engine, Jinja allows the template designer to call functions with arguments on objects.

What is Autoescape in Jinja2?

When autoescaping is enabled, Jinja2 will filter input strings to escape any HTML content submitted via template variables. Without escaping HTML input the application becomes vulnerable to Cross Site Scripting (XSS) attacks. Unfortunately, autoescaping is False by default.


2 Answers

The error message that you've received is explained in the stack trace. Specifically, here:

File "/home/asdoylejr/microblog/app/templates/index.html", line 7, in block "content" {{form.hidden_tag()}}  File "/home/asdoylejr/microblog/flask/lib/python2.7/site-packages/jinja2/environment.py", line 397, in getattr return getattr(obj, attribute)  UndefinedError: 'form' is undefined 

The error message is coming from Jinja, which is saying that form is undefined. Your template tries to use form...

... {% block content %} <h1>Hi, {{g.user.nickname}}!</h1> <form action="" method="post" name="post">     {{form.hidden_tag()}} <table>     ... 

...but you've never passed it as part of your render_template method (you've only defined title, user and posts)...

return render_template("index.html",         title = 'Home',         user = user,         posts = posts) 
like image 114
Mark Hildreth Avatar answered Oct 02 '22 01:10

Mark Hildreth


You should pass form as the context variable. Try this:

@app.route('/', methods = ['GET', 'POST']) @app.route('/index', methods = ['GET', 'POST']) @login_required def index():     form = PostForm()     if form.validate_on_submit():         post = Post(body = form.post.data, timestamp = datetime.utcnow(), author = g.user)         db.session.add(post)         db.session.commit()         flash('Your post is now live!')         return redirect(url_for('index'))     posts = g.user.followed_posts().all()     return render_template("index.html",         title = 'Home',         user = user,         posts = posts,         form = form) 
like image 44
zero323 Avatar answered Oct 02 '22 02:10

zero323