I am unable to get data from flask forms [duplicate] - python

This question already has an answer here:
Form is never valid with WTForms
(1 answer)
Closed 3 years ago.
I have like a search bar built with wtforms, but I don't know for some reason I am unable to fetch data or value entered in the search bar. I tried almost everything from online tutorials but just couldn't find the solution. Below is my code examples.
For my search bar, I have tried form.search.data and request.form['search'] too but it's not working.
#flask_app.py
from flask import Flask, render_template, url_for, flash, redirect, request
from forms import SearchForm
app = Flask(__name__)
app.config['SECRET_KEY'] = '791628bb0b13ce0c676dfde'
#app.route('/')
#app.route('/home')
def home():
return render_template('home.html')
#app.route('/search', methods= ['GET', 'POST'])
def search():
form = SearchForm()
if form.validate_on_submit():
if form.search.data == 'admin':
return redirect(url_for('home'))
return render_template('search.html', form= form)
if __name__ == "__main__":
app.run(debug=True)
#forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
class SearchForm(FlaskForm):
search = StringField('search', validators=[DataRequired()])
submit = SubmitField('Search')
#search.html
{% extends 'layout.html' %}
{% block content %}
<form action="" class="form-inline mt-4" method="POST">
<div class="form-group">
{{form.search(class= 'form-control', placeholder= 'Enter term to search')}}
{{form.submit(class= 'btn btn-outline-primary')}}
</div>
</form>
{%endblock%}
#home.html
{% extends 'layout.html' %}
{% block content %}
<h1>Welcome to homepage!</h1>
{%endblock%}
Is there any bug? I expect form.search.data should be able to fetch data from search bar.

You're not inserting the CSRF field in the HTML form which can be done via form.hidden_tag()
#search.html
{% extends 'layout.html' %}
{% block content %}
<form action="" class="form-inline mt-4" method="POST">
{{ form.hidden_tag() }}
<div class="form-group">
{{form.search(class='form-control', placeholder= 'Enter term to search')}}
{{form.submit(class='btn btn-outline-primary')}}
</div>
</form>
{% endblock %}
See this

Related

AttributeError: 'LoginForm' object has no attribute 'validate_on_sumbit'

I have done a registration and login page registration page works fine but login page when i Click on create account i get object has no attribute.
application.py
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import Length,EqualTo,InputRequired,ValidationError
from models import User
#app.route('/login', methods=['GET', 'POST'])
def login():
login_form = LoginForm()
if login_form.validate_on_sumbit():
return "Logged in, finally!"
return render_template('login.html', form=login_form)
#wtform_fields.py
class LoginForm(FlaskForm):
"""Login Form """
username = StringField('username_label',validators=[InputRequired(message="username required")])
password = PasswordField('password_label',validators=[InputRequired(message="Password required"),invalid_credentials])
submit = SubmitField('Login')
login.html
{% from 'form_helper.html' import DisplayField %}
{% extends "prelogin-layout.html" %}
{% block title %} Registration {% endblock %}
{% block content %}
<h3>Create your account</h3>
<hr>
<form action="{{ url_for('index') }}", method="POST" >
{{DisplayField(form.username, 'Username', autocomplete='off',autofocus=true)}}
{{DisplayField(form.password, 'Password')}}
{{DisplayField(form.confirm, 'Confirm Password')}}
<div class="form-group">
<input type="submit" value="Create" >
</div>
{{form.csrf_token}}
</form>
{% endblock %}
ErrorLog
in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "C:\Users\Catalyst\Desktop\Python\chatAp\application.py", line 18, in login
if login_form.validate_on_sumbit():
AttributeError: 'LoginForm' object has no attribute 'validate_on_sumbit'
I'm new at flask can you direct e where I'm mistaken
PS I'm working with flaskwtf V1.0.1
Change the line that adds submit in login.html from
<div class="form-group">
<input type="submit" value="Create" >
</div>
to
<div class="form-group">
{{DisplayField(form.submit, 'Create')}}
</div>
If you are using Flask WTF all fields in the form must come from the library.
P.S.
I don't know where you got the confirm variable to check the password from.
It may not work for you either. If you want the user to enter the password twice, read here: wtforms.validators.EqualTo

Raising an error in WTForm using jinja2

I'm trying to raise an error in Jinja2, in a WTForm, the error should be raised if url input is not validated, but when i submit an invalide url, i get a popup saying "Please enter a url".
how do i pass the default popup and add a custom error message ?
here is the main py:
from datetime import datetime
from flask import Flask, render_template, url_for, request, redirect,flash
from logging import DEBUG
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from flask.ext.wtf.html5 import URLField
from wtforms.validators import DataRequired , url
app = Flask(__name__)
app.logger.setLevel(DEBUG)
app.config['SECRET_KEY']='{#\x8d\x90\xbf\x89n\x06%`I\xfa(d\xc2\x0e\xfa\xb7>\x81?\x86\x7f\x1e'
#app.route('/')
#app.route('/index')
def index():
return render_template('base.html')
#app.route('/add', methods=['GET','POST'])
def add():
return render_template('add.html')
# HERE IS THE LOGIN FORM
class Login(FlaskForm):
username = StringField('username')
password = PasswordField('password')
url = URLField('url', validators=[DataRequired(),url()])
#app.route('/form', methods=['GET','POST'])
def form():
form = Login()
if form.validate_on_submit():
url = form.url.data
return redirect(url_for('index'))
return render_template('form.html',form = form )
if __name__ =='__main__':
app.run(debug=True)
and here is the template:
<!DOCTYPE html>
<html>
<head>
<title>form</title>
</head>
<body>
<h1>Hello !</h1>
<form method="POST" action="{{url_for('form')}}">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
{{ form.username.label }}
{{ form.username }}
{{ form.password.label }}
{{ form.password }}
{{ form.url.label }}
{{ form.url }}
{% if form.url.errors %} <p> {{error}}</p> {% endif %}
<button type="submit">Submit</button>
</form>
</body>
</html>
Because you're using the data type URLField, this is rendered as a HTML5 "url" form field type.
Your browser recognises this and performs its own validation on the data submitted:
There is no way for you to override this - it's built in to the browser.
If you need to show a custom error message, you might be able to use a TextField instead, and provide your own URL validation logic.
Add your own message instead of default message in your form defination.
url = URLField('url', validators=[DataRequired(),url(message="Please enter a valid url (e.g.-http://example.com/)")])
As Matt Healy before mentiones, it is the browser that validates URLField.
So if you want a custom error message use StringField (TextField is outdated). If required, a custom message can be used as shown below message='text to display'.
Example:
class XYZForm(FlaskForm):
url = StringField('url', validators=[DataRequired(),url(message='Please enter valid URL')])
description = StringField('description')
Of course the *.html should include code to output an error to the page:
<ul>
{% for error in form.url.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
It seems like novalidate attribute works for your case.

Validate that a WTForms BooleanField is checked

I am creating a form using Flask-WTForms.
I am using a BooleanField so that a user can indicate they agree terms.
I cannot validate the BooleanField upon submission to ensure that it has been checked. I have tried using Required(), DataRequired() and custom validation but in each case I have not received a validation error.
Here are the nuts and bolts of the application:
from flask import Flask, render_template, session, redirect, url_for, flash
from flask_wtf import Form
from wtforms import BooleanField, SubmitField
from wtforms.validators import Required, DataRequired
from flask_bootstrap import Bootstrap
app = Flask(__name__)
app.config['SECRET_KEY'] = 'impossibletoknow'
bootstrap = Bootstrap(app)
class AgreeForm(Form):
agreement = BooleanField('I agree.', validators=[DataRequired()])
submit = SubmitField('Submit')
#app.route('/', methods=['GET', 'POST'])
def index():
form = AgreeForm()
if form.validate_on_submit():
agreement = form.agreement.data
if agreement is True:
flash('You agreed!')
return redirect(url_for('index', form=form))
form.agreement.data = None
agreement = False
return render_template('index.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
And here is the index.html template...
{% import "bootstrap/wtf.html" as wtf %}
{% block content %}
<div class="container">
{% for message in get_flashed_messages() %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ message }}
</div>
{% endfor %}
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
Any suggestions would be gratefully received.
Works for me— you do need to use DataRequired() (Required is being deprecated):
from flask import Flask, render_template
from flask_wtf import Form
from wtforms import BooleanField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.secret_key = 'STACKOVERFLOW'
class ExampleForm(Form):
checkbox = BooleanField('Agree?', validators=[DataRequired(), ])
#app.route('/', methods=['post', 'get'])
def home():
form = ExampleForm()
if form.validate_on_submit():
return str(form.checkbox.data)
else:
return render_template('example.html', form=form)
if __name__ == '__main__':
app.run(debug=True, port=5060)
Template:
<form method="post">
{{ form.hidden_tag() }}
{{ form.checkbox() }}
<button type="submit">Go!</button>
</form>
<h1>Form Errors</h1>
{{ form.errors }}
You do not have to include DataRequired() in your form, because it does not make sense, being a boolean. You must take of the incoming form data in the post method by saying if true.

Why validation not working on form request?

I am learning flask and made a small application. Now I am trying to learn form. I used a simple code to validate a name request and it should give error when the field remains empty. But it isn't giving one.
Main file :
from flask import Flask, render_template
from flask.ext.moment import Moment
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField, validators
import requests
import json
from datetime import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'abcd'
moment = Moment(app)
class Nameform(Form):
name = StringField("whats your name?", [validators.Required()])
submit = SubmitField('submit')
#app.route('/')
#app.route('/index')
def index():
api_call = requests.get('https://api.stackexchange.com/2.2/users/moderators?order=desc&sort=reputation&site=stackoverflow') # api call to stack for user with highest scores in des order
var_1 = json.loads(api_call.text)
var_2 = [{'link': value['link'], 'name': value['display_name'], 'user_id': value['user_id']} for value in var_1['items']]
return render_template('index.html', posts=var_2, current_time=datetime.utcnow())
#app.route('/user/<id>/<user_name>')
def user(id, user_name):
print id
api_call = requests.get('https://api.stackexchange.com//2.2/users/'+id+'/reputation?site=stackoverflow') # api call for reputation of click user
var_1 = json.loads(api_call.text)
return render_template('reputation.html', result=var_1, user_name=user_name)
#app.route('/test', methods=['GET', 'POST'])
def user_form():
name = None
form = Nameform()
if form.validate_on_submit():
name = form.name.data
form.name.data = ''
return render_template('test_form.html', form=form, name=name)
if __name__ == '__main__':
app.run(debug=True)
Template for rendering:
<div class="page-header">
<h1>Hello, {% if name!= None %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
<form method=post>
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }}
</form>
Why it is not throwing any error? when the field remains empty
You can render the error messages using form.errors. Note that you're also missing your CSRF token, which is required for validation since you didn't disable WTF_CSRF_ENABLED, so I've added {{ form.csrf_token }}. See CSRF Protection.
<div class="page-header">
<h1>Hello, {% if name!= None %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
{% for field in form.errors %}
{% for error in form.errors[field] %}
<div class="error">{{ error }}</div>
{% endfor %}
{% endfor %}
<form method=post>
{{ form.csrf_token }}
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }}
</form>
I think you have not included the novalidate attribute with form.
The novalidate attribute is used to tell the web browser to not apply validation to the fields in this form, which effectively leaves this task to the Flask application running in the server.
For Sample code

'forms.ContactForm object' has no attribute 'hidden_tag'

I am trying to create a contact form using flask but keep getting this error when the page is rendered.
'forms.ContactForm object' has no attribute 'hidden_tag'
Here are my files:
contact.html
{% extends "layout.html" %}
{% block content %}
<h2>Contact</h2>
<form action="{{ url_for('contact') }}" method=post>
{{ form.hidden_tag() }}
{{ form.name.label }}
{{ form.name }}
{{ form.email.label }}
{{ form.email }}
{{ form.subject.label }}
{{ form.subject }}
{{ form.message.label }}
{{ form.message }}
{{ form.submit }}
</form>
{% endblock %}
forms.py
from flask.ext.wtf import Form
from wtforms import Form, TextField, TextAreaField, SubmitField, validators
class ContactForm(Form):
name = TextField("Name", [validators.Required()])
email = TextField("Email",[validators.Required(), validators.email()])
subject = TextField("Subject", [validators.Required()])
message = TextAreaField("Message", [validators.Required()])
submit = SubmitField("Send")
routes.py
from flask import Flask, render_template, request
from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'development key'
#app.route('/')
def home():
return render_template('home.html')
#app.route('/about')
def about():
return render_template('about.html')
#app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm()
if request.method == 'POST':
return 'Form posted.'
elif request.method == 'GET':
return render_template('contact.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
All the other page templates are working perfectly fine. Any advice would be awesome! Thanks for the help!
I just fixed this problem as well.
Your problem is that you imported Form twice, rendering your flask-wtf Form import useless.
from flask_wtf import Form
from wtforms import Form, TextField, TextAreaField, SubmitField, validators
# ^^^ Remove
Only the flask-wtf extension has the special Form class which can handle CSRF automatically / other stuff.
I tried to fix this, too.
After removing brackets "()" appended after hidden_tag, it works.
{{ form.hidden_tag }}
It took me some time to fix this.
First import Form, fields, bootstrap as:
from flask_wtf import Form
from wtforms import StringField #etc
from flask_bootstrap import Bootstrap
Config secret key and bootstrap
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret key'
Bootstrap(app)
create your form as your used to:
class ContactForm(Form):
name = TextField("Name", [validators.Required()])
email = TextField("Email",[validators.Required(), validators.email()])
subject = TextField("Subject", [validators.Required()])
message = TextAreaField("Message", [validators.Required()])
submit = SubmitField("Send")
Nothing special in the routing aswell, just return it normaly.
In the html:
{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% if form %}
{{ wtf.quick_form(form, ) }}
{% endif %}
And that's it. Hope you find some (or all) of it useful.
Update for #Yuji'Tomita'Tomita answer :
You should import FlaskForm instead of Form
from flask_wtf import FlaskForm
from wtforms import TextField, TextAreaField, SubmitField, validators
The error that you're seeing is telling you that forms.ContactForm has no method called "hidden_tag". You're referencing that method on the 6th line of contact.html like this:
{{ form.hidden_tag() }}
According to the flask documentation, this is the correct way to implement CSRF protection.
I would start by removing the line that references "form.hidden_tag()", then see if your form works. Then go back and implement CSRF protection per those instructions from the documentation.

Categories

Resources