I have a form that is setup as below and ultimately, the error I get in debug mode is sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed. I understand why, but I would like this error to get presented to the user so they know the issue.
class RegistrationForm(FlaskForm):
company_url = StringField('Company Website', validators=[DataRequired(), URL(message='Must be a valid URL')])
password = PasswordField(
'Password', validators=[DataRequired(), EqualTo('pass_confirm',
message='Passwords must match')]
)
pass_confirm = PasswordField('Confirm Password', validators=[DataRequired()])
submit = SubmitField('Register!')
However, when an incorrect URL structure is entered into the form and submitted, I cannot get it to flash an error message in the html page for the user. The html page is below. I will place the base.html below as well.
{% extends "base.html" %}
{% block content %}
<form method="POST">
{{form.hidden_tag()}}
{{form.company_url.label}}{{form.company_url()}}<br>
{{form.password.label}}{{form.password()}}<br>
{{form.pass_confirm.label}}{{form.pass_confirm()}}<br>
{{form.submit()}}
</form>
{% endblock %}
<!DOCTYPE html>
<html>
<head>
...some code here
</head>
<body>
<!-- Just an image -->
<nav class="navbar navbar-dark bg-dark">
<span class="align-bottom text-light">Creating connections, saving time</span>
</nav>
{% with messages = get_flashed_messages() %} {% if messages %} {% for
message in messages %}
<div class="alert alert-warning alert-dismissible" role="alert">
<button
type="button"
class="close"
data-dismiss="alert"
aria-label="Close"
>
<span aria-hidden="true">×</span>
</button>
{{message}}
</div>
{% endfor %} {% endif %} {% endwith %} {% block content %} {% endblock %}
</body>
</html>
The views.py is:
#app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = Buyers(
company_url=form.company_url.data,
password=form.password.data
)
db.session.add(user)
db.session.commit()
flash("Thank you for registering.")
return redirect(url_for('login'))
return render_template('register.html', form=form)
How do I error handle in forms to make sure the user is aware that they have entered a URL with an incorrect structure? I am in debug mode and right now, the register.html page just basically reloads without any message as to why. Thank you!
views.py :
import validators
#app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
isUrlValid=validators.url(form.company_url.data)
if isUrlValid==True:
user = Buyers(
company_url=form.company_url.data,
password=form.password.data
)
db.session.add(user)
db.session.commit()
flash("Thank you for registering.")
return redirect(url_for('login'))
else:
flash("URL is not valid. Please enter a valid URL")
return redirect(url_for('register'))
return render_template('register.html', form=form)
Related
After trying for a week to fix the issue I decided to post the question here.
I migrated my application (python+flask) from cloud foundry to Azure.
After that suddenly my user login and registration functionalities stopped working.
After checking a bit more, at first, it was displaying an error message that my CSRF token was invalid.
I disabled CRSF globally to test. The registration function was working again, however, the login functionality was still odd. I showed 4 kinds of behavior:
1 - accessing the Login page directly and inserting the right email and password redirects you to index, as intended, but current_user.is_authenticated = false;
2 - accessing the Login page and inputting the wrong password or email returns you to the login page but with no alert that password or email was wrong;
3- accessing a page behind login requirement and using the right email and password will just reload the login page with the redirect in the URL and do nothing;
4 - same as 3 but with wrong password or email results in the same thing;
After a while, I enabled the CSRF again and now the error message changed to CSRF token missing.
Maybe it is not related, but the issues began after I migrated to Azure (it worked in the beginning, but it stopped working after a while...I can't remember if it was before or after I started enforcing HTTPS).
Here is my code:
init.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
import os
from flask_login import LoginManager
from itsdangerous import URLSafeTimedSerializer
app = Flask(__name__)
app.config['MAIL_SERVER'] = os.getenv('MAIL_SERVER')
app.config['MAIL_PORT'] = os.getenv('MAIL_PORT')
app.config['MAIL_USERNAME'] = os.getenv('MAIL_USER')
app.config['MAIL_PASSWORD'] = os.getenv('MAIL_PASSWORD')
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('MYSQL_URI')
app.config['SECRET_KEY'] = os.urandom(32)
app.config['SERVER_NAME'] = os.getenv('SERVER_NAME')
db = SQLAlchemy(app)
db.init_app(app)
migrate.init_app(app, db)
manager = Manager(app)
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
login = LoginManager()
login.init_app(app)
login.session_protection = "strong"
login_serializer = URLSafeTimedSerializer(app.secret_key)
from app import views, models
if __name__ == '__main__':
app.run(debug=True)
on models.py:
#login.user_loader
def load_user(user_id):
print("User loader called with id %s" % user_id)
return User.query.get(int(user_id))
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=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)
my forms on views.py:
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
remember_me = BooleanField('Remember Me')
submit = SubmitField('Sign In')
class RegistrationForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
password2 = PasswordField(
'Repeat Password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('Register')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is not None:
raise ValidationError('Please use a different email address.')
my login, register, and logout functions on views.:
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
print(form.errors)
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.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('index')
return redirect(next_page)
flash('Login Failed')
return render_template('login.html', title='Sign In', form=form, is_auth=current_user.is_authenticated)
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('index'))
#app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = RegistrationForm()
print(form.errors)
if form.validate_on_submit():
user = User(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)
my login template:
{% extends "base.html" %}
{% block content %}
{% endblock %}
{% block body %}
<h1>Sign In</h1>
<div class="box box-default">
<div class="box-body">
{{ form.hidden_tag() }}
<form action="" method="post">
<p>
{{ form.email.label }}<br>
{{ form.email(size=64) }}<br>
{% for error in form.email.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
</p>
<p>
<p>{{ form.remember_me() }}
{{ form.remember_me.label }}</p>
<p>{{ form.submit() }}</p>
</form>
<p>New User? Click to Register!</p>
</div>
</div>
{% endblock %}
my register template:
{% extends "base.html" %}
{% block content %}
{% endblock %}
{% block body %}
<h1>Register</h1>
<div class="box box-default">
<div class="box-header with-border">
<form action="" method="post">
{{ form.hidden_tag() }}
<p>
{{ form.email.label }}<br>
{{ form.email(size=64) }}<br>
{% for error in form.email.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}<br>
{% for error in form.password.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
</p>
<p>
{{ form.password2.label }}<br>
{{ form.password2(size=32) }}<br>
{% for error in form.password2.errors %}
<span style="color: red;">[{{ error }}]</span>
{% endfor %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
</p>
<p>{{ form.submit() }}</p>
</form>
</div>
</div>
{% endblock %}
I apologize in advance if the code doesn't look professional, I'm still a junior and a bit new with flask.
Does anyone see what might be causing the described issue?
I'm using python 3.8, flask 1.1.2, flask-wtf 0.14.3, and flask-login 0.5.0.
I tried everything from the other similar questions on StackOverflow and from this blog, but nothing worked so far or seems to be related to my issue (so please consider this before marking this question as a duplicate).
Thank you very much in advance for your help.
edit: grammar
I talked with Miguel Grinberg about the issue and he pointed out the problem was with:
app.config['SECRET_KEY'] = os.urandom(32)
This part of the code was making so, every time the app was restarted the tokens would be invalidated.
I just changed it to a static environment variable and it is now working fine again.
Can someone please help resolving RadioField Post issue in below code snippet
As below code is not moving form.validate_on_submit()
**forms.py**
class validatingSPLForm(FlaskForm):
srcfile = FileField('Select Source ZIP', validators=[FileRequired(), FileAllowed(['zip'], 'Only ZIP files are allowed')])
submit = SubmitField("Validate")
proceed = IntegerField()
SPLFiles = RadioField('SPL', choices=[])
archiveresult = []
**routes.py**
app.route('/validatingSPLForm', methods=['GET', 'POST'])
def validatingSPLForm():
form = validatingSPLForm()
if request.method == 'POST':
if form.validate_on_submit():
form.SPLFiles.choices = [(elem.name, elem.des) for elem in form.archiveresult]
**validatingSPLForm.html**
{% extends "layout.html" %}
{% block content %}
<div class="content-section">
<form method="POST" action="" enctype="multipart/form-data">
</form>
</div>
{% endblock content %}
{% block content1 %}
<div class="content-section">
<h6><b class="text-success">"{{ form.srcfile.data.filename }}"</b> is valid, select one of the below SPL for further validation </h6>
{{ form.SPLFiles() }}
</div>
{% endblock content1 %}
For context, here is the view.py
from .forms import SignIn
...
def sign_in_view(request, *args, **kwargs):
form = SignIn(request.POST or None)
if form.is_valid():
form.save()
form = SignIn(request.POST or None)
context = {
'form': form
}
return render(request, "accounts/sign_in.html", context)
here is the HTML file for accounts/sign_in.html
{% extends "accounts/base.html" %}
{% block title %}
<title>Log-in</title>
{% endblock %}
{% block content %}
<h1 align="center">Sign in</h1>
<hr/>
<form method="POST" action="http://127.0.0.1:8000/home/"> # currently in localhost
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Sign in">
</form>
{% endblock content %}
Without the attribute action="http://127.0.0.1:8000/home/" in my form tag in accounts/sign_in.html, I manage to successfully add a user to the database by typing in the required parameters on the browser.
However, with the attribute action="http://127.0.0.1:8000/home/", I was redirected to the URL, but when I checked the database in /admin/, I was unable to see the user there.
I don't know if the form isn't saved, or I had just done some stupid mistake.
Thanks.
Action attribute is not for redirection after sending the form. It should be the url attached to the view that is responsible for handling a form. What is the url of your sign_in_view? If it is for example /sign-in/ that should be value of action attribute. If you want to redirect user after signing in, do it in your sign_in_view:
if form.is_valid():
...
return redirect('/home/')
Here is a link for Django docs that includes all the useful information about forms:
https://docs.djangoproject.com/en/3.0/topics/forms/
This is a better way for the user to register.
view.py
def sign_in_view(request):
form = SignIn(request.POST or None)
if form.is_valid():
user = form.save()
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('/')
context = {
'form': form
}
return render(request, "accounts/sign_in.html", context)
and than in you template you can do this
{% extends "accounts/base.html" %}
{% block title %}
<title>Log-in</title>
{% endblock %}
{% block content %}
<h1 align="center">Sign in</h1>
<hr/>
<form method="POST" action=""> # currently in localhost
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Sign in">
</form>
{% endblock content %}
I was running some tests in Django to see if form.errors raises all types of errors in the form (which it does).
Now here's where things went south:
If i try to sign up with an existing email/username (just checking the efficiency) more than once , i get this
Forbidden (403)
CSRF verification failed. Request aborted.
Help text : (all those conditions are met.)
I think these tests break the csrf_token.
So i don't know if the problem is coming from my code or the csrf_token is just doing its job by protecting the owner of that username/email.
Did anyone encounter an issue like this before ?
SignUp View
class SignUp(View):
def get(self, request):
form = MyModelCreation()
return render(
request,
'signup.html',
{'form': form}
)
def post(self, request):
form = MyModelCreation(request.POST)
if form.is_valid():
user = form.save(commit=False)
user.is_active = False # Create an inactive user
user.save()
# Send a confirmation Email
# Generate a token for the new user --tokens.py--
current_site = get_current_site(request)
mail_subject = 'Activate your profile account.'
message = render_to_string('account_activation_email.html', {
'user': user,
'domain': current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(user.pk)).decode(),
'token': user_token.make_token(user),
})
receiver = form.cleaned_data.get('email')
email = EmailMessage(
mail_subject, message, to=[receiver]
)
email.send()
return redirect("account_activation_sent")
else:
return render_to_response(
'signup.html',
{"form": form},
RequestContext(request)
)
SignUp Template
{% extends 'base_test.html' %}
{% block title %}My Site | Sign Up{% endblock title %}
{% block content %}
<div class="padding">
<h2>Sign up : <small>*ALL FIELDS ARE REQUIRED</small></h2>
<form method="post" class="form">
{% csrf_token %}
{% for field in form %}
<p>
{{ field.label_tag }}<br>
{{ field }}
{% for error in field.errors %}
<p style="color: red">{{ error }}</p>
{% endfor %}
</p>
{% endfor %}
<button class="btn btn-primary btn-lg" type="submit">Sign up</button>
</form>
</div>
{% endblock %}
well i fixed it by switching back to render(), i think render_to_response() requires some additional data that i don't know of.
return render(request, 'signup.html', {'form': form})
Thank you !
I have a problem with if/else condition into my template.
I have a simple form and confirmation button. User should input text in this form, then should press button and only after that, user will see other part of page.
This is my template code:
{% extends "home/base.html" %}
{% load staticfiles %}
{{% block body %}
<h1 align="center">Analyzed text</h1>
<form class="form" action="analyze" method="post">
<div id="form">
<dd><textarea id="textarea" name="q" rows=10 cols=55 placeholder=" Input your text in japanese here ..."></textarea>
<dd><input class="myButton" type="submit" value="Analyze">
</div>
</form>
<div class=page>
{% if 'q' != None %}
{% include "kanji_analyzer/show_results.html" %}
{% endif %}
</div>
{% endblock %}}
views.py
from django.shortcuts import render_to_response
from kanji_analyzer.logic_part.kanji_analyzer import KanjiesText
def start_kanji(request):
return render_to_response('kanji_analyzer/main.html')
def show_entries():
global analyzed_text
global list_of_percents
global list_of_find_kanjies
return render_to_response('show_entries.html', {'analyzed_text': analyzed_text, 'list_of_percents': list_of_percents,
'list_of_find_kanjies': list_of_find_kanjies,})
def send_text(request):
if 'q' in request.POST:
q = request.POST['q']
a = KanjiesText(request.POST['q'])
a.remove_spaces_from_text()
list_of_percents = a.take_percent_count()
list_of_find_kanjies = a.list_find_kanjies()
for i in range(0,5):
if len(list_of_find_kanjies[i]) == 0:
list_of_find_kanjies[i] = ''
return render_to_response('kanji_analyzer/main.html', {'q': q, 'list_of_percents': list_of_percents,
'list_of_find_kanjies': list_of_find_kanjies,})
else:
q = "your form is empty"
return render_to_response('kanji_analyzer/main.html', {'q': q},)
This block if/else doesn't work. 'q' - value with user's text