I am writing an application which is managing forms using Flask as backend framework.
When I fill data in the form(username and password) correctly, instead of the program returning 'Form sucessfully submitted', I get the following error:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
Why is that happening?
Notice 1: I put a HTML file in templates directory, so that is not a cause of the error
Notice 2: I wrote here only the code which is relevant to this problem
Here is the code:
1) application.py
from flask import Flask, render_template, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import InputRequired, Email, Length, AnyOf
from flask_bootstrap import Bootstrap
app = Flask(__name__)
Bootstrap(app)
app.config['SECRET_KEY'] = 'somePassword'
class LoginForm(FlaskForm):
username = StringField('username', validators=[InputRequired(), Email(message='I don\'t like your email.')])
password = PasswordField('password', validators=[InputRequired(), Length(min=5, max=10), AnyOf(['secret', 'password'])])
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
return 'Form sucessfully submitted'
return render_template('loginForm1.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
2) loginForm1.html
{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}
WTForms
{% endblock %}
{% block content %}
<div class="container">
<form method="POST" action="/">
<dl>
{{ wtf.quick_form(form)}}
<input type="submit" value="Login" class="btn btn-info">
</dl>
</form>
</div>
{% endblock %}
You've defined the route as /login but your form is posting to /.
Related
I'm creating a flask/python/html project that asks the user for their name. I'm trying to use wtforms to validate the input.
This is the html (mainScraper.html):
{% extends 'base.html' %}
{% block head %}
<link rel ="stylesheet" href = "mainScraper.css">
{% endblock %}
{% block body %}
<h1> This is the main page </h1>
<p> Please enter your name: </p>
<br/>
<form action = "mainScraper", method = "POST">
{{ form.csrf_token }}
{{ form.username.label }}
{{ form.username }}
{{ form.submit }}
</form>
{% endblock %}
And this is the flask/python:
from flask import Flask, render_template, request, redirect, url_for, session, flash
from flask_wtf import FlaskForm
from wtforms import SubmitField, StringField
from wtforms.validators import data_required, length
app = Flask(__name__)
app.secret_key = "34Secret56"
#app.route('/')
def index():
return render_template('mainScraper.html')
name = ' '
class NameForm(FlaskForm):
username = StringField('Name', validators = [data_required(),length(min = 1)])
submit = SubmitField('Submit')
#app.route('/mainScraper', methods = ['POST', 'GET'])
def mainScraper():
form = NameForm()
if form.validate_on_submit():
global name
name = form.username.data
return render_template('general.html')
return render_template('mainScraper.html', form=form)
I want to make sure at least one character is submitted before moving on to the next html page (from the mainScraper.html to the general.html).
But I'm getting this error from my mainScraper.html file: "jinja2.exceptions.UndefinedError: 'form' is undefined" and I'm confused as to why, because I defined 'form' in the corresponding method of the python file, mainScraper. And I’m not sure how else I should validate my forms in html because most online videos or websites I’ve seen use flask-WTF or WTForms with {{ form.csrf_token}} in a html file
Also I’m not using an IDE for the python file, but React for the html file, is that a problem?
If so, what IDE do you suggest I use for the python and html file?
I am learning Flask and I've incurred into a supposedly beginners error:
Method Not Allowed The method is not allowed for the requested URL.
The thing is that, even though I reduce the code into something really simple, I can't find it. As far as I can see, the POST method is correctly set up (I will use comments to explain it).
The files are:
flaskblog.py
from flask import Flask, render_template, url_for, flash, redirect, request
from forms import RegistrationForm
app = Flask(__name__)
app.config['SECRET_KEY'] = '5791628bb0b13ce0c676dfde280ba245'
#app.route("/")
#app.route('/home', methods=['GET', 'POST']) # As one can see, the POST method is written there.
def home():
form = RegistrationForm()
return render_template('home.html', title='Home', form=form)
if __name__ == '__main__':
app.run(debug=True)
home.html
{% extends "layout.html" %}
{% block content %}
<div class="content-section">
<form method="POST" action=""> # The POST method is written there as well.
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Join Today</legend>
<div class="form-group">
{{ form.username.label(class="form-control-label") }}
{{ form.username(class="form-control form-control-lg") }}
</div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
</div>
{% endblock content %}
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, BooleanField
from wtforms.validators import DataRequired, Length, Email, EqualTo
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
submit = SubmitField('Sign Up')
I get the error when I submit the form, any help would be greatly appreciated!
Thanks!
You're not distinguishing between GET and POST requests appropriately in your home route. Flask defaults the incoming request, from the client, as a GET request since your definitions are off. However, this is an issue because the incoming request is actually a POST request as we can see from your form:
<form method="POST" action=""> # The POST method is written there as well.
Perhaps you could try modifying your home route to handle both POST/GET requests approriately, something along the lines of:
#app.route("/")
#app.route('/home', methods=['GET', 'POST'])
def home():
form = RegistrationForm()
# POST request
if form.validate_on_submit():
return redirect(url_for(<route>)) #route to be rendered if form properly validates
# GET request
return render_template('home.html', title='Home', form=form)
Hopefully that helps!
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)
I need to prepopulate form fields with database (dataset) values.
The problem is that I don't know how to send the argument to the form class.
forms.py
# coding: utf-8
from db import produtosalca as produtos ##dataset imports db['table']
from flask_wtf import FlaskForm
from wtforms import TextField, BooleanField, SubmitField, TextAreaField, validators, ValidationError
class ProductForm(FlaskForm,produto):
descricao = TextField("Nome", default=produto.Descricao)
classificacaoFiscal = TextField("NCM", default=produto.ClassificacaoFiscal)
mva = TextField("MVA",default=produto.MVA)
app.py
# coding: utf-8
import os
from werkzeug import secure_filename
from flask import (
Flask, request, send_from_directory, render_template, current_app, flash
)
from db import produtosalca
from forms import ContactForm, ProductForm
app = Flask("alcax")
PROJECT_ROOT = os.path.abspath(os.path.dirname(__file__))
app.config['MEDIA_ROOT'] = os.path.join(PROJECT_ROOT, 'media_files')
app.secret_key = 'development key'
#app.route('/productform', methods=['GET','POST'])
def productform(product):
form = ProductForm(request.form,product) ## here i was gonna send product
if request.method == 'POST':
'posted'
elif request.method == 'GET':
return render_template('productform.html', form=form.content())
Well everything I tried always get me the error
'produto' is not defined
I'm a beginner in py. Have been researching all night long. Thanks in advance.
Note that class ProductForm(FlaskForm) means ProductForm inherets from FlaskForm. A simple solution for your case would be as follows:
forms.py:
from flask_wtf import FlaskForm
from wtforms import TextField
class ProductForm(FlaskForm):
descricao = TextField("Nome")
classificacaoFiscal = TextField("NCM")
mva = TextField("MVA")
app.py:
from flask import Flask, render_template, redirect, request
from forms import ProductForm
app = Flask(__name__)
app.secret_key = 'development key'
#app.route('/productform', methods=['GET','POST'])
def productform():
form = ProductForm(descricao='default_descricao', classificacaoFiscal='default_classificacaoFiscal', mva='default_mva')
if form.validate_on_submit():
form = ProductForm(request.form)
# Do something with your form and redirect the user to some page.
return render_template('productform.html', form=form)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
templates/_formhelpers.html
{% 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 %}
templates/productform.html
<html !DOCTYPE>
<head>
<title>Flask WTF</title>
</head>
<body>
{% from "_formhelpers.html" import render_field %}
<form method="POST" action="/submit">
<dl>
{{ form.hidden_tag() }}
{{ render_field(form.descricao, size=20) }}
{{ render_field(form.classificacaoFiscal, size=20) }}
{{ render_field(form.mva, size=20) }}
</dl>
<input type="submit" value="Go">
</form>
</body>
</html>
Edit to take into account the new queries in the comments below:
forms.py:
class ProductForm(FlaskForm):
descricao = TextField("Nome")
classificacaoFiscal = TextField("NCM")
mva = TextField("MVA")
# ...
def __init__(self, *args, **kwargs):
super(ProductForm, self).__init__(*args, **kwargs)
if 'product' in kwargs:
self.descricao.data = kwargs['product'][0]
self.classificacaoFiscal.data = kwargs['product'][1]
self.mva.data = kwargs['product'][2]
# ...
app.py:
#app.route('/productform', methods=['GET','POST'])
def productform():
# product to be retrieved from your database
form = ProductForm(product=product)
if form.validate_on_submit():
form = ProductForm(request.form)
# Do something with your form and redirect the user to some page.
return render_template('productform.html', form=form)
I'm getting a werkzeug.routing.BuildError when I go to my "login.html" page. The problem seems to be the "action=" attribute in the template. Originally it was action={{url_for('login')}}. Although the docs show it done this way it doesn't seem to work. When I change it to action="/login" or action="#" it works correctly. The question is why? I was under the impression that the correct way was the action={{url_for('login')}}?
Before I broke my code up into packages (everything in single py file) it worked correctly.
BTW, most of this code is from Miguel Grindberg's GREAT book "Flask Web Development". The code I'm having problems with is my own that I added going through the book. I'm on WinXP and using the most up to date Flask. Here is my code below:
flasky\app\main\views.py:
from flask import render_template, session, redirect, url_for, current_app, flash
from .. import db
from ..models import User
from ..email import send_email, post_mail
from . import main
from .forms import NameForm, RegForm
#main.route('/login', methods=['GET', 'POST'])
def login():
form = RegForm()
if form.validate_on_submit():
session['name'] = form.username.data
session['logged_in'] = True
return redirect(url_for('success'))
return render_template('login.html', form=form)
flasky\app\templates\login.html:
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Sign Up{% endblock %}
{% block content %}
{{ super() }}
<div class="well">
<h1 align="center">Sign-In</h1>
</div>
<div class="container">
<form class="form form-horizontal" action="{{url_for('login')}}" method="post">
{{form.hidden_tag()}}
{{wtf.form_field(form.username)}}
{{wtf.form_field(form.email)}}
{{wtf.form_field(form.password)}}
{{wtf.form_field(form.bool)}}
{{wtf.form_field(form.submit)}}
</form>
</div>
{% endblock %}
<!-- action= {{url_for('login')}} doesn't work. . ."#" and "\login" work-->
flasky\app\main\forms.py:
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField, PasswordField, BooleanField, SubmitField
from wtforms.validators import Required, Email
class RegForm(Form):
username = StringField('Username', validators=[Required()])
email = StringField('Email Address', validators=[Email()])
password = PasswordField('Password', validators=[Required()])
bool = BooleanField("I Agree To Your Terms of Services", validators=[Required()])
submit = SubmitField('Submit')
A BuildError is raised when the url_for() method cannot locate an endpoint that fits the description. In this case, no login endpoint was found to be registered with the Flask app object.
You appear to have registered the login route with a Blueprint named main instead; you need to use the blueprint name in the endpoint name:
{{ url_for('main.login') }}
If the template is only ever used by routes in the main blueprint, you can make it relative too by starting the name with a .:
{{ url_for('.login') }}
See the Building URLs section of the Blueprints documentation.