jinja2.exceptions.UndefinedError: 'forms.SignupForm object' has no attribute 'hidden_tag'

Question:

This code used to work and has since become deprecated.

It is now giving an error" "jinja2.exceptions.UndefinedError: ‘forms.SignupForm object’ has no attribute ‘hidden_tag’".

I have been researching and can’t seem to identify what has changed. Can anyone help?

**forms.py**
from flask_wtf import Form
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, Email, Length

class SignupForm(Form):
  first_name = StringField('First name', validators=[DataRequired("Please enter your first name.")])
  last_name = StringField('Last name', validators=[DataRequired("Please enter your last name.")])
  email = StringField('Email', validators=[DataRequired("Please enter your email address."), Email("Please enter your email address.")])
  password = PasswordField('Password', validators=[DataRequired("Please enter a password."), Length(min=6, message="Passwords must be 6 characters or more.")])
  submit = SubmitField('Sign up')

class LoginForm(Form):
  email = StringField('Email', validators=[DataRequired("Please enter your email address."), Email("Please enter your email address.")])
  password = PasswordField('Password', validators=[DataRequired("Please enter a password.")])
  submit = SubmitField("Sign in")

class AddressForm(Form):
  address = StringField('Address', validators=[DataRequired("Please enter an address.")])
  submit = SubmitField("Search")



**routes.py**
from flask import Flask, render_template, request, session, redirect, url_for
from models import db, User, Place
from forms import SignupForm, LoginForm, AddressForm

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///test.db"
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():
  if 'email' in session:
    return redirect(url_for('home'))

  form = SignupForm()

  if request.method == "POST":
    if form.validate() == False:
      return render_template('signup.html', form=form)
    else:
      newuser = User(form.first_name.data, form.last_name.data, form.email.data, form.password.data)
      db.session.add(newuser)
      db.session.commit()

      session['email'] = newuser.email
      return redirect(url_for('home'))

  elif request.method == "GET":
    return render_template('signup.html', form=form)

@app.route("/login", methods=["GET", "POST"])
def login():
  if 'email' in session:
    return redirect(url_for('home'))

  form = LoginForm()

  if request.method == "POST":
    if form.validate() == False:
      return render_template("login.html", form=form)
    else:
      email = form.email.data
      password = form.password.data

      user = User.query.filter_by(email=email).first()
      if user is not None and user.check_password(password):
        session['email'] = form.email.data
        return redirect(url_for('home'))
      else:
        return redirect(url_for('login'))

  elif request.method == 'GET':
    return render_template('login.html', form=form)

@app.route("/logout")
def logout():
  session.pop('email', None)
  return redirect(url_for('index'))

@app.route("/home", methods=["GET", "POST"])
def home():
  if 'email' not in session:
    return redirect(url_for('login'))

  form = AddressForm()

  places = []
  my_coordinates = (-27.5447, 153.1060)

  if request.method == 'POST':
    if form.validate() == False:
      return render_template('home.html', form=form)
    else:
      # get the address
      address = form.address.data

      # query for places around it
      p = Place()
      my_coordinates = p.address_to_latlng(address)
      places = p.query(address)

      # return those results
      return render_template('home.html', form=form, my_coordinates=my_coordinates, places=places)

  elif request.method == 'GET':
    return render_template("home.html", form=form, my_coordinates=my_coordinates, places=places)

if __name__ == "__main__":
  app.run()





**signup.html**
{% extends "layout.html" %}

{% block content %}
  <main class="container signup-section">
    <div class="section-content">
      <h2>Create an account</h2>

      <form method="POST" action="/signup">
        {{ form.hidden_tag() }}

        <div class="form-group">
          {{ form.first_name.label }}

          {% if form.first_name.errors %}
            {% for error in form.first_name.errors %}
              <p class="error-message">{{ error }}</p>
            {% endfor %}
          {% endif %}

          {{ form.first_name }}
        </div>


login.html

{% extends "layout.html" %}

{% block content %}
  <main class="container signup-section">
    <div class="section-content">
      <h2>Log in</h2>

      <form method="POST" action="/login">
        {{ form.hidden_tag() }}

        <div class="form-group">
          {{ form.email.label }}
          {{ form.email }}
        </div>

        <div class="form-group">
          {{ form.password.label }}
          {{ form.password }}
        </div>

        {{ form.submit(class="btn-primary") }}
  <a href="{{ url_for('logout') }}" class="btn-primary">Back</a>
      </form>
    </div>

  </main>
{% endblock %}


        <div class="form-group">
          {{ form.last_name.label }}

          {% if form.last_name.errors %}
            {% for error in form.last_name.errors %}
              <p class="error-message">{{ error }}</p>
            {% endfor %}
          {% endif %}

          {{ form.last_name }}
        </div>

        <div class="form-group">
          {{ form.email.label }}

          {% if form.email.errors %}
            {% for error in form.email.errors %}
              <p class="error-message">{{ error }}</p>
            {% endfor %}
          {% endif %}

          {{ form.email }}
        </div>

        <div class="form-group">
          {{ form.password.label }}

          {% if form.password.errors %}
            {% for error in form.password.errors %}
              <p class="error-message">{{ error }}</p>
            {% endfor %}
          {% endif %}

          {{ form.password }}
        </div>

        {{ form.submit(class="btn-primary") }}
              <a href="{{ url_for('logout') }}" class="btn-primary">Back</a>
      </form>

    </div>
  </main>
{% endblock %}

I tried a few of the fixes on stackoverflow. None have worked.

Asked By: Asking

||

Answers:

You code looks fine except for the Form Object, try to change the import line to:

from flask_wtf import FlaskForm

in you form classes inherit from FaskForm instead of the Form class.
In order to generate the csrf token, you must have a secret key, this is usually the same as your Flask app secret key. If you want to use another secret key, config it:

Answered By: Elie Saad
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.