Flask submit form on POST: '405 Method not allowed' - python

Hi I am a bit confused about a flask application. I have a route / to welcomepage that generates a ux_uuid then passes it to the form. Now, after I submit the form I want the ID (ux_uuid) passed on as well. However, in all cases (form.validate==false or even if all is ok) it ends up in a 405 error - Method not allowed. The methods=['GET','POST'] has the ['POST'] method is there so I don't understand why even if request.method == 'POST' breaks?
app.py:
import logging, os
from flask import Flask, json, make_response, render_template, request, session, redirect, url_for, jsonify
from ux.forms import QuestionForm
from flask_wtf.csrf import CSRFProtect
import sqlite3
app = Flask(__name__, static_url_path='')
app.secret_key = "NSA secret key"
csrf = CSRFProtect()
csrf.init_app(app)
#app.route('/', methods=['GET', 'POST'])
def welcomepage():
# Here is the random user ID generated by some random function but
# can be set to some string to test:
ux_uuid = 'TETST_ID' #or set this to ux_uuid='TestUserID'
return render_template('welcomepage.html', ux_uuid=ux_uuid)
#app.route('/form1/<ux_uuid>', methods=['GET', 'POST'])
def form1(ux_uuid):
form = QuestionForm()
if request.method == 'POST':
if form.validate() == False:
print("VALIDATE ME !")
return render_template('/form1.html/<ux_uuid>', form=form, ux_uuid=ux_uuid)
else:
#
#mylist = json.dumps(form.first_question)
print('I STORED ALL THE FORM DATA IN THE SQLITE3 DB here - and GO ON TO:')
return render_template('signup.html', ux_uuid=ux_uuid)
elif request.method == 'GET':
return render_template('form1.html', form=form, ux_uuid=ux_uuid)
return render_template('form1.html')
# turn on debug=true to see error messages
if __name__ == "__main__":
app.run(debug=True)
This is the /ux/forms.py:
from flask_wtf import Form
from wtforms import SelectMultipleField, SubmitField, RadioField
from wtforms.validators import DataRequired, Email, Length
class QuestionForm(Form):
first_question = SelectMultipleField('What is your favourite food? Select all that apply:', choices=[('pizza','pizza'), ('more pizza', 'more pizza'), ('burger', 'burger'), ('salad', 'salad'), ('fries', 'fries'), ('pasta', 'pasta')], validators=[DataRequired()])
second_question = RadioField('How many coins do you have?', choices=[('0','0'), ('1-5','1-5'), ('5-10','5-20'), ('More than 20', 'More than 20')], validators=[DataRequired()])
third_question = RadioField('Do you like chocolate?', choices=[('Yes', 'Yes'), ('No', 'No')], validators=[DataRequired()])
submit = SubmitField('Submit & Continue')
and the form1.html:
<!DOCTYPE html>
<html>
<head>
<title>PREVIOUS EXPERIENCE</title>
</head>
<body>
<main class="container signup-section">
<div class="section-content">
<h2>Please Answer the following questions</h2>
<form method="POST" action="/form1">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.first_question.label }}
{% if form.first_question.errors %}
{% for error in form.first_question.errors %}
<p class="error-message">{{ error }}</p>
{% endfor %}
{% endif %}
{{ form.first_question }}
</div>
<div class="form-group">
{{ form.second_question.label }}
{% if form.second_question.errors %}
{% for error in form.second_question.errors %}
<p class="error-message">{{ error }}</p>
{% endfor %}
{% endif %}
{{ form.second_question }}
</div>
<div class="form-group">
{{ form.third_question.label }}
{% if form.third_question.errors %}
{% for error in form.third_question.errors %}
<p class="error-message">{{ error }}</p>
{% endfor %}
{% endif %}
{{ form.third_question }}
</div>
{{ form.submit(class="btn-primary") }}
</form>
</div>
<p>ID TEST:</p>
{{ ux_uuid }}
</main>
</body>
</html>
and the welcomepage:
<!DOCTYPE html>
<html>
<head>
<title>WELCOMEPAGE</title>
</head>
<body><p> ENTRY PAGE / START WELCOME </p>
Continue</body>
</html>
Here are all files to test: stack.zip

Related

Retrieve hx-include value from HTMX request with Flask

I'm trying to send a client side value to the server when a HTMX request is made. I can't seem to get the value using request.args.get('cardCount')or request.form.get('cardCount').
I'm using flask_htmx to catch HTMX requests server side and render partial html. I need to get the cardCount from the dom so I can increment the new card being added correctly. If I don't add 'cards-3-front' and 'cards-3-back' to the html id and name the wtforms FieldList will not save dynamically added textarea content to the db.
Here is the form:
# NOTECARD FORMS
class CardForm(Form):
front = TextAreaField('front', validators=[InputRequired()])
back = TextAreaField('back', validators=[InputRequired()])
class NoteForm(FlaskForm):
title = StringField('Title', validators=[InputRequired(), Length(max=35)])
cards = FieldList(FormField(CardForm), min_entries=3)
Here is the view:
#views.route('/create', methods=['GET', 'POST'])
#login_required
def create():
user_img = get_user_img()
form = NoteForm()
if htmx:
count = request.args.get('cardCount')
return render_template("./partials/notecard.html", count=count)
if request.method == 'POST':
if form.validate_on_submit():
fronts = [bleach.clean(card.front.data) for card in form.cards]
backs = [bleach.clean(card.back.data) for card in form.cards]
set = dict(zip(fronts, backs))
db.session.add(Notes(title=bleach.clean(form.title.data), content=set, user_id=current_user.id))
db.session.commit()
flash('New Notecard Set Created!', 'success')
return redirect(url_for('views.dashboard'))
else:
flash('All notecard fields must be filled in', 'warning')
return render_template("create.html", user_img=user_img, form=form)
Here is the htmx request I'm trying to send from the template:
<div name="cardCount">3</div>
<button hx-get="/create" hx-include="[name='cardCount']" hx-target="#newCards" hx-swap="beforeend" class="btn"></button>
It seems to me that your approach using hx-include fails due to the fact that you want to include the content of a div element and not the value of an input element.
Below is an example where you can add and remove form fields using htmx. The entire form is replaced by an htmx call.
I use an input field of type hidden to determine the number of input fields.
To determine whether fields should be added or removed, an additional header is used using hx-headers.
Depending on the data transmitted via htmx, the form is changed and replaced as a whole, with the entries made being retained.
Flask (app.py)
from flask import (
Flask,
redirect,
render_template,
request,
url_for
)
from flask_htmx import HTMX
from flask_wtf import FlaskForm, Form
from wtforms import (
FieldList,
FormField,
StringField,
TextAreaField
)
from wtforms.validators import (
DataRequired,
Length
)
app = Flask(__name__)
app.secret_key = 'your secret here'
htmx = HTMX(app)
class CardForm(Form):
front = TextAreaField('Front', validators=[DataRequired()])
back = TextAreaField('Back', validators=[DataRequired()])
class NoteForm(FlaskForm):
title = StringField('Title', validators=[DataRequired(), Length(min=3, max=35)])
cards = FieldList(FormField(CardForm), min_entries=1)
#app.route('/', methods=['GET', 'POST'])
def index():
form = NoteForm(request.form)
num_fields = max(0, request.form.get('count', 1, type=int))
if htmx:
form.validate()
hx_func = request.headers.get('Hx-Func', 'DEL')
if hx_func.lower() == 'del':
num_fields = max(1, num_fields - 1)
form.cards.min_entries = num_fields
form.cards.entries = form.cards.entries[:form.cards.min_entries]
else:
num_fields += 1
form.cards.min_entries = num_fields
while len(form.cards.entries) < form.cards.min_entries:
form.cards.append_entry()
return render_template('partials/form.html', **locals())
else:
if form.validate_on_submit():
print(form.title.data, form.cards.data)
# Use the form data here.
return render_template('index.html', **locals())
HTML Template (index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Index</title>
</head>
<body>
{% include 'partials/form.html' %}
<script src="https://unpkg.com/htmx.org#1.8.5"></script>
</body>
</html>
HTML Template (partials/form.html)
<form name="my-form" method="post">
{{ form.csrf_token }}
<div>
{{ form.title.label() }}
{{ form.title() }}
{% if form.title.errors -%}
<ul>
{% for error in form.title.errors -%}
<li>{{ error }}</li>
{% endfor -%}
</ul>
{% endif -%}
</div>
{% for subform in form.cards -%}
{% for field in subform -%}
<div>
{{ field.label() }}
{{ field() }}
{% if field.errors -%}
<ul>
{% for error in field.errors -%}
<li>{{ error }}</li>
{% endfor -%}
</ul>
{% endif -%}
</div>
{% endfor -%}
{% endfor -%}
<input type="hidden" name="count" value="{{ num_fields }}" />
<button
type="button"
hx-post="/"
hx-target="[name='my-form']"
hx-headers='{"Hx-Func": "DEL"}'
hx-swap="outerHTML"
>Less</button>
<button
type="button"
hx-post="/"
hx-target="[name='my-form']"
hx-headers='{"Hx-Func": "ADD"}'
hx-swap="outerHTML"
>More</button>
<button type="submit">Submit</button>
</form>

how to access min_entries in Flask WTF, in another file?

please tell me how to access min_entries correctly, I need it to generate fields for the form.
My codes:
forms.py:
class ToSend(FlaskForm):
send = FieldList(FormField(AddEquipment), min_entries=())
equipment_add.py:
#app.route('/equipment_add', methods=['GET', 'POST'])
def addEquipment():
update = 0
if request.method == "POST":
update = int(request.form['update'])
print(update)
form = ToSend()
form.send.min_entries = update
return render_template('equipment_add.html', form=form, update=update)
return render_template('equipment_add.html', update=update)
And so I turn form.send.min_entries = update and there's a mistake:
while len(self.entries) < self.min_entries:
TypeError: '<' not supported between instances of 'int' and 'tuple'
What am I doing wrong?
The problem arises because you didn't specify an integer as the value for the minimum number when defining the FieldList, but a pair of brackets.
If you don't enter a value here, the default value of 0 will be used automatically.
As I understand your code, you want to dynamically add form fields depending on the number requested by another form.
You can solve your problem in different ways. I'll show you two options, using a GET request to query how many fields the form should contain.
The first option is to add the fields manually using append_entry().
from flask import (
Flask,
render_template,
request
)
from flask_wtf import FlaskForm, Form
from wtforms import FieldList, FormField, StringField, SubmitField
app = Flask(__name__)
app.secret_key = 'your secret here'
class EquipmentForm(Form):
name = StringField('Name')
class AddEquipmentForm(FlaskForm):
items = FieldList(FormField(EquipmentForm))
submit = SubmitField('Add Items')
#app.route('/equipment/add', methods=['GET', 'POST'])
def equipment_add():
num_fields = max(0, request.args.get('cnt', 0, type=int))
form = AddEquipmentForm(request.form)
form.items.min_entries = num_fields
while len(form.items.entries) < form.items.min_entries:
form.items.append_entry()
if form.validate_on_submit():
print(form.items.data)
return render_template('equipment_add.html', **locals())
The second option uses a factory to recreate the form for each request and sets the min_entries attribute of the FieldList.
from flask import (
Flask,
render_template,
request
)
from flask_wtf import FlaskForm, Form
from wtforms import FieldList, FormField, StringField, SubmitField
app = Flask(__name__)
app.secret_key = 'your secret here'
class EquipmentForm(Form):
name = StringField('Name')
class AddEquipmentForm(FlaskForm):
submit = SubmitField('Add Items')
#app.route('/equipment/add', methods=['GET', 'POST'])
def equipment_add():
def _factory(num_items):
class F(AddEquipmentForm): pass
setattr(F, 'items', FieldList(FormField(EquipmentForm), min_entries=num_items))
return F
num_fields = max(0, request.args.get('cnt', 0, type=int))
form = _factory(num_fields)(request.form)
if form.validate_on_submit():
print(form.items.data)
return render_template('equipment_add.html', **locals())
The template would then look like this for both examples.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<form>
<label for="cnt">Add Item Count</label>
<input type="number" name="cnt" value="{{ num_fields }}" min="0" />
<input type="submit" />
</form>
<hr/>
{% if form.items | count > 0 -%}
<form method='post'>
{{ form.csrf_token }}
{% for subform in form.items -%}
{% for field in subform -%}
<div class="">
{{ field.label() }}
{{ field() }}
{% if field.errors -%}
<ul>
{% for error in field.errors -%}
<li>{{ error }}</li>
{% endfor -%}
</ul>
{% endif -%}
</div>
{% endfor -%}
{% endfor -%}
{{ form.submit() }}
</form>
{% endif -%}
</body>
</html>

Page is not redirecting and db.session.add() and db.session.commit() commands are not working

I've just started learning flask. I'm trying to handle a form for user registration. But inside my routes.py, the form's data isn't getting pushed to the database, and also the page isn't redirecting after the click on the submit button. There is no error or any warning. The action just does not get performed and the register page just gets re-loaded.
I'm attaching the codes of the files below. The demo is the folder where my HTML templates and .py files are saved.
#run.py : located outside the root(demo) folder
from demo import app
if __name__ == '__main__':
app.run(debug=True)
-------------------------------------------------------------------------------------
#__init__.py
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///demo.db'
app.config['SECRET_KEY'] = 'df159ba68c3577847ef3dfef'
db = SQLAlchemy(app)
from demo import routes
-------------------------------------------------------------------------------------
#model.py
from demo import db
class Item(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), nullable=False, unique=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(60), nullable=False)
def __repr__(self):
return f'Item {self.username}'
------------------------------------------------------------------------------------
#form.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
class RegisterForm(FlaskForm):
username = StringField(label='Username')
email = StringField(label='Email')
password = PasswordField(label='Password')
submit = SubmitField(label='Create Account')
-------------------------------------------------------------------------------------
#routes.py
from demo import app
from flask import render_template, redirect, url_for
from demo.model import Item
from demo.form import RegisterForm
from demo import db
#app.route('/')
#app.route('/home')
def hello_world():
return render_template('home.html', item_name="number")
#app.route('/info')
def second_page():
items = Item.query.all()
return render_template('info.html', items=items)
#app.route('/register', methods=['GET', 'POST'])
def registration_page():
form = RegisterForm()
if form.validate_on_submit():
user_to_create = Item(username=form.username.data,
email=form.email.data,
password=form.password.data)
db.session.add(user_to_create)
db.session.commit()
return redirect(url_for('second_page'))
return render_template('register.html', form=form)
-----------------------------------------------------------------------------------
#register.html
{% extends 'base.html' %}
{% block title %}
Registration page
{% endblock %}
{% block content %}
<form method="POST" >
{{ form.username.label() }}
{{ form.username(placeholder='Enter Your Username') }}
{{ form.email.label() }}
{{ form.email(placeholder='Enter Your Email') }}
{{ form.password.label() }}
{{ form.password(placeholder='Enter Your Password') }}
{{ form.submit() }}
</form>
{% endblock %}
----------------------------------------------------------------------------------
#info.html :The page from second_page() function in routes.py
{% extends 'base.html' %}
{% block title %}
This is Info page
{% endblock %}
{% block content %}
<h1>you are in the info page</h1>
<h1>Welcome to this page</h1>
<h1>Great day!</h1>
{% for item in items %}
<p>{{ item.username }} - {{ item.email }}</p>
{% endfor %}
{% endblock %}
These are the files from my project. Please help me clear this functionality error. Thanks in advance.
Your form is never validated because are you have not used csrf token.
You can try printing print(form.errors) before and after the if statement
[...]
form = RegisterForm()
print(form.errors)
if form.validate_on_submit():
user_to_create = Item(username=form.username.data,
email=form.email.data,
password=form.password.data)
db.session.add(user_to_create)
db.session.commit()
return redirect(url_for('second_page'))
print(form.errors)
return render_template('register.html', form=form)
first it will give no error but after submiting it will give no crsf token
In html You can add {{form.csrf_token}}
<form method="POST" >
{{ form.csrf_token }} // add this and this should work
{{ form.username.label() }}
{{ form.username(placeholder='Enter Your Username') }}
{{ form.email.label() }}
{{ form.email(placeholder='Enter Your Email') }}

How to take form data from Flask template and pass to HTML page [duplicate]

This question already has answers here:
How to pass a variable between Flask pages?
(2 answers)
Closed 9 months ago.
Hello everyone I'm new to Flask and I cant wrap my mind around this concept for some reason. What I essentially have so far is a user registration page. In my flaskschool.py I'm creating a form called the RegistrationForm. I'm then creating a template for that form in my register.html. In my view function I'm then rendering that template and printing out the value for User I took in from the form out to my HTML page. My goal is to present the user with the form they just used as well as Welcome message with whatever value they just entered for username in the form. An advice helps, Thanks!
flapp.py
from flask import Flask, redirect, url_for, render_template, request, session, flash
from flask_wtf import FlaskForm
from flaskschool import DateForm, RegistrationForm
from upload import UploadForm
app = Flask(__name__)
# for decrypting session data
app.secret_key = "testb"
#app.route("/")
def home():
return render_template("index.html")
## test site for user registration/
#app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = form.username.data
email = form.email.data
return render_template('register.html', form=form, user=user)
if __name__ == "__main__":
app.run(debug=True)
flaskschool.py
from wtforms import Form, BooleanField, StringField, PasswordField, validators
from wtforms.fields.html5 import DateField, DateTimeField
from flask_wtf import FlaskForm
from datetime import date
## playing with custom validators
def validate_username(form, field):
if len(field.data) > 25:
raise validator.ValidationError("Username must be less than 25 characters")
class RegistrationForm(FlaskForm):
username = StringField('Username', [validate_username])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [validators.DataRequired(),
validators.EqualTo('confirm', message='Passwords must match')])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.DataRequired()])
enter code here
register.html
{% from "_formhelpers.html" import render_field %}
<form method="POST" action="/register">
<dl>
</dl>
{{ render_field(form.username) }}
{{ render_field(form.email) }}
{{ render_field(form.password) }}
{{ render_field(form.confirm) }}
{{ render_field(form.accept_tos) }}
</dl>
<p><input type=submit value=submit>
</div>
</form>
<br>
<h1>Welcome: {{user}}</h1>
<br>
If you want to retrieve a registered user's information, it will be necessary for you to work with a database. You will be able to query the database to retrieve a user's information, and present it in a template.
You have a lot going on well for you above except for some minor modifications that you will need to do, and a few things you can add. I have started from the very beginning so you can follow through:
Create a simple application to ensure that every part of flask is working
Configure your application to work with web forms and a database
Create a simple database (I will use sqlite. You can use any other if you want)
Create registration and login form structures
Display the forms in HTML templates
Render those templates using view functions
Consider using the structure below when building your application. It is convinient to follow the principle of separation of concerns when building your application in that parts of your application are clustered in modules.
project
| --- flapp.py
| --- config.py
| --- .flaskenv
| --- app/
| --- __init__.py
| --- routes.py
| --- models.py
| --- forms.py
| --- templates/
| --- base.html
| --- home.html
| --- register.html
| --- login.html
| --- static/
1. Create an application instance and ensure the initial project is working
Install flask, flask-wtf, flask-login, email-validator, python-dotev in your virtual environment
Initialize these packages in __init__.py file:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from config import Config
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
login = LoginManager(app)
login.login_view = 'login'
from app import routes, models
I have added login.login_view = 'login' which will be used to protect the Home page from being accessed by anonymous users. I have also imported the Config class from the config module which we will create in a section below.
# flapp.py
from app import app
This file acts as an entry point to your flask application.
# routes.py
from app import app
#app.route('/')
#app.route('/home')
def home:
return 'home'
The home() view function will return the text "home" when you run the application.
# .flaskenv
FLASK_APP=school.py
FLASK_ENV=development
FLASK_DEBUG=True
Flask expects these variables before starting the server. The package python-dotenv installed earlier is used to load them instead of having to pass each variable in the terminal before typing flask run.
When you run the application, you should see "Home".
2. Configure the application
Install flask-sqlalchemy, flask-migrate. They are needed to run and manage your database. Respective variables are initialized from os.environ.get.
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'difficult-to-guess'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
Feel free to change the database to whichever you want. SECRET_KEY is needed when you work with web forms.
3. Create a database
# models.py
from app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
def __repr__(self):
return '<User {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
#login.user_loader
def load_user(id):
return User.query.get(int(id))
To create this database, run these commands in your terminal:
# create a migration repository
(venv)$ flask db init
# Create a migration script
(venv)$ flask db migrate -m 'user table'
# Apply the changes
(venv)$ flask db upgrade
This will create a User table with columns for username, email and a hashed password. It is advised not to be storing a user's password in the database, rather store it as a representation of it in the form of a hash.
4. Simple form structure
The register form will look like this:
# register.html
{% extends "base.html" %}
{% block content %}
<h1>Register</h1>
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.email.label }}<br>
{{ form.email(size=32) }}<br>
{% for error in form.email.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.password2.label }}<br>
{{ form.password2(size=32) }}<br>
{% for error in form.password2.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
The login form will look like this:
# login.html
{% extends "base.html" %}
{% block content %}
<h1>Sign In</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}<br>
{% for error in form.username.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
</p>
<p>{{ form.remember_me() }} {{ form.remember_me.label }}</p>
<p>{{ form.submit() }}</p>
</form>
<p>New here? Register now!</p>
{% endblock %}
Both these templates are inheriting the structure of the base template using the keyword extends. So, this base.html file will look like this:
# base.html
<html>
<head>
{% if title %}
<title>{{ title }} - demo</title>
{% else %}
<title>so demo</title>
{% endif %}
</head>
<body>
<div>
SO Demo:
Home
{% if current_user.is_anonymous %}
Login
{% else %}
Logout
{% endif %}
</div>
<hr>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
Every time a user tries to register or log in to their accounts, flash message will appear. This is shown in the base template.
The home page will look like this:
# home.html
{% extends "base.html" %}
{% block content %}
<p>
Hi {{ current_user.username }},<br><br>
These are your details:
</p>
<p>
Name: {{ current_user.username }}<br>
Email: {{ current_user.email }}<br>
Hashed Password: {{ current_user.password_hash }}
</p>
{% endblock %}
We are displaying the current_user's details as stored in the database.
The view functions that handle all these information includes the home(), register(), login() and additionally logout() as seen here:
from flask import render_template, flash, redirect, url_for, request
from app import app, db
from app.forms import LoginForm, RegistrationForm
from flask_login import current_user, login_user, logout_user
from app.models import User
from flask_login import login_required
from werkzeug.urls import url_parse
#app.route('/')
#app.route('/home')
#login_required
def home():
return render_template('home.html')
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user is None or not user.check_password(form.password.data):
flash('Invalid username or password')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('home')
return redirect(next_page)
return render_template('login.html', title='Sign In', form=form)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('home'))
#app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('home'))
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
You should have this:

No validation on submit Flask

For some reason, form.validate_on_submit() does not return anything.
from flask import Flask
from flask_wtf import FlaskForm
from wtforms import StringField, DecimalField, validators
from flask import render_template
app = Flask(__name__)
app.config.update(dict(
SECRET_KEY="super awesome key"
))
class MyForm(FlaskForm):
name = StringField('Product name', [validators.InputRequired(), validators.Length(min=0, max=30)])
#app.route('/', methods=['GET', 'POST'])
def index():
form = MyForm()
if form.validate_on_submit():
return "Mission accomplished!"
return render_template('submit.html', form=form)
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Add new grocery product</h1>
<p>Provide appropriate product details</p>
<form method="POST" action="/">
{{ form.csrf_token }}
{{ render_field(form.name.label) }} {{ form.name(size=20) }}<br>
<input type="submit" value="Go">
</form>
</body>
</html>
The app itself is supposed to gather user input in specific form and insert this via SQLAlchemy into database. Output is supposed to:
Return "Mission accomplished!" if validation succeeded
Return validation of which field failed and display error msg "This field is required" on the submit.html template
EDIT
Duo some success with the code, I make another edit to the question. It seems that macro isn't displaying error message for appropriate field if the validation fails.
I.E. if Field name is empty, macro should create and display error message ( This Field cannot be empty) by itself.
FINAL EDIT
I managed to find the solution. Submit.html template seems to cause the issue with macro if render_field looks like this:
{{ render_field(form.name.label) }}
instaed of this:
{{ render_field(form.name) }}
#This might help
from flask import Flask
from flask_wtf import FlaskForm
#from wtform import SubmitField
from wtforms import StringField, DecimalField, validators,SubmitField
from flask import render_template
app = Flask(__name__)
app.config.update(dict(
SECRET_KEY="super awesome key"
))
class MyForm(FlaskForm):
you need to make an edit to your validators like this
name = StringField('Product name', validators = [InputRequired(), , Length(min=0, max=30)])
#create submit option in your flask form
submit = SubmitField("Submit")
#app.route('/', methods=['GET', 'POST'])
def index():
form = MyForm()
if form.validate_on_submit():
return "Mission accomplished!"
return render_template('submit.html', form=form)

Categories