title: Flask: AttributeError: 'UnboundField' object has no attribute '__call__'?
body: <p>Why do I get this error? What is the UnboundField and what do I need to know in order to fix and avoid this problem in the future?</p>
  
  <p><strong>Debug output when I visit <a href="http://127.0.0.1:5000/signup" rel="noreferrer">http://127.0.0.1:5000/signup</a>:</strong></p>
  
  <pre><code>AttributeError
  
  AttributeError: 'UnboundField' object has no attribute '__call__'
  Traceback (most recent call last)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 2000, in __call__
  
      return self.wsgi_app(environ, start_response)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 1991, in wsgi_app
  
      response = self.make_response(self.handle_exception(e))
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 1567, in handle_exception
  
      reraise(exc_type, exc_value, tb)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 1988, in wsgi_app
  
      response = self.full_dispatch_request()
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 1641, in full_dispatch_request
  
      rv = self.handle_user_exception(e)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 1544, in handle_user_exception
  
      reraise(exc_type, exc_value, tb)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 1639, in full_dispatch_request
  
      rv = self.dispatch_request()
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\app.py", line 1625, in dispatch_request
  
      return self.view_functions[rule.endpoint](**req.view_args)
  
      File "C:\Users\combatmath\Apps\ocrbox\routes.py", line 27, in signup
  
      return render_template("signup.html", form=form)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\templating.py", line 134, in render_template
  
      context, ctx.app)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\flask\templating.py", line 116, in _render
  
      rv = template.render(context)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\jinja2\environment.py", line 989, in render
  
      return self.environment.handle_exception(exc_info, True)
  
      File "C:\Users\combatmath\Envs\default\lib\site-packages\jinja2\environment.py", line 754, in handle_exception
  
      reraise(exc_type, exc_value, tb)
  
      File "C:\Users\combatmath\Apps\ocrbox\templates\signup.html", line 1, in top-level template code
  
      {% extends "base.html" %}
  
      File "C:\Users\combatmath\Apps\ocrbox\templates\base.html", line 9, in top-level template code
  
      {% block content %}{% endblock %}
  
      File "C:\Users\combatmath\Apps\ocrbox\templates\signup.html", line 30, in block "content"
  
      {{ form.submit(class="btn-primary") }}
  
      AttributeError: 'UnboundField' object has no attribute '__call__'
  </code></pre>
  
  <p><strong>signup.html:</strong></p>
  
  <pre><code>{% extends "base.html" %}
  
  {% block title %}Join ocrbox!{% endblock %}
  
  {% block content %}
      &lt;main class="container signup-section"&gt;
          &lt;div class="section-content"&gt;
              &lt;h2&gt;Create an account&lt;/h2&gt;
  
              &lt;form method="POST" action="/signup"&gt;
  
  
                  &lt;div class="form-group"&gt;
                      {{ form.first_name.label }}
                      {{ form.first_name }}
                  &lt;/div&gt;
                  &lt;div class="form-group"&gt;
                      {{ form.last_name.label }}
                      {{ form.last_name }}
                  &lt;/div&gt;
                  &lt;div class="form-group"&gt;
                      {{ form.email.label }}
                      {{ form.email }}
                  &lt;/div&gt;
                  &lt;div class="form-group"&gt;
                      {{ form.password.label }}
                      {{ form.password }}
                  &lt;/div&gt;
  
                  {{ form.submit(class="btn-primary") }}
              &lt;/form&gt;
          &lt;/div&gt;
      &lt;/main&gt;
  {% endblock %}
  </code></pre>
  
  <p><strong>routes.py:</strong></p>
  
  <pre><code>from flask import Flask, render_template, request
  from models import db
  from forms import SignupForm
  
  app = Flask(__name__)
  
  app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://localhost/ocrbox'
  db.init_app(app)
  
  app.secret_key = "development-key"
  
  @app.route("/")
  def index():
      return render_template("index.html")
  
  @app.route("/about")
  def about():
      return render_template("about.html")
  
  @app.route("/signup", methods=['GET', 'POST'])
  def signup():
      form = SignupForm
  
      if request.method == 'POST':
          return "Success!"
      elif request.method == 'GET':
          return render_template("signup.html", form=form)
  
  if __name__ == "__main__":
      app.run(debug=True)
  </code></pre>
  
  <p><strong>forms.py:</strong></p>
  
  <pre><code>from flask_wtf import Form
  from wtforms import StringField, PasswordField, SubmitField
  
  class SignupForm(Form):
      first_name = StringField('First name')
      last_name = StringField('Last name')
      email = StringField('Email')
      password = PasswordField('Password')
      submit = SubmitField('Sign up')
  </code></pre>
  
  <p><strong>models.py:</strong></p>
  
  <pre><code>from flask_sqlalchemy import SQLAlchemy
  from werkzeug import generate_password_hash, check_password_hash
  
  db = SQLAlchemy()
  
  class User(db.Model):
      __tablename__ = 'users'
      uid = db.Column(db.Integer, primary_key=True)
      firstname = db.Column(db.String(100))
      lastname = db.Column(db.String(100))
      email = db.Column(db.String(120), unique=True)
      pwdhash = db.Column(db.String(54))
  
      def __init__(self, firstname, lastname, email, password):
          self.firstname = firstname.title()
          self.lastname = lastname.title()
          self.email = email.lower()
          self.set_password(password)
  
      def set_password(self, password):
          self.pwdhash = generate_password_hash(password)
  
      def check_password(self, password):
          return check_password_hash(self.pwdhash, password)
  </code></pre>