Register and Edit profile in a Flask App
Contents
Create sign up form
In your 'forms.py' file we need to create a form for the sign-up process. You should have created 'forms.py' when you created your login form. You will also need to import the DateField and SelectField:
from wtforms import StringField, PasswordField, SubmitField, DateField, SelectField
Now for the flaskform, add the following:
class SignUpForm(FlaskForm):
username = StringField('Username', validators=[DataRequired()])
password = PasswordField('Password', validators=[DataRequired()])
confirm = PasswordField('Confirm Password', validators=[DataRequired()])
email = StringField('Email', validators=[])
DOB = DateField('DOB', format='%Y-%m-%d')
MF = SelectField('Gender', choices=[('M','Male'), ('F','Female')])
submit = SubmitField('Sign In')
Create sign up template
My WebApp was created using Visual Studio, and it already created a 'layout' template and then separate 'html' files for each page. If you already have templates set up you should copy one of the 'html' files for a page and edit it to this:
{% extends "layout.html" %}
{% block content %}
<h1>Sign In</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ form.username(size=32) }}
</p>
<p>
{{ form.password.label }}<br>
{{ form.password(size=32) }}
</p>
<p>
{{ form.confirm.label }}<br>
{{ form.confirm(size=32) }}
</p>
<p>
{{ form.email.label }}<br>
{{ form.email(size=32) }}
</p>
<p>
{{ form.DOB.label }}<br>
{{ form.DOB(size=32) }}
</p>
<p>
{{ form.MF.label }}<br>
{{ form.MF() }}
</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
Create sign up route
You will need to add 'SignUpForm' to the current form import. Add the following to create a signup route:
@app.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignUpForm()
if form.validate_on_submit():
return redirect('/')
return render_template('signup.html', title='Sign Up', form=form)
At the moment, the form will reload if it is invalid (remember some fields are set to be required). Currently if the form is valid it redirects to the root of the web app. We need to add additional checks, because the password and the confirm must be the same and we might want to test if the username currently exists.
Insert data into users table
The current 'signup' route and method will only check the form is valid, we now need to do the rest. Edit your current method to the following:
@app.route('/signup', methods=['GET', 'POST'])
def signup():
form = SignUpForm()
if form.validate_on_submit():
#get datam from form
username = form.username.data
password = form.password.data
confirm = form.confirm.data
email = form.email.data
dob = form.DOB.data
mf = form.MF.data
#check confirm & password are the same
if password == confirm:
#check current users in database
db = Database()
sql ="select * from users where UserID='%s'" % (username)
rows=db.select(sql)
#if username isn't in use then 0 rows will be returned
if(len(rows)==0):
#create database connection and add the new user
db=Database()
sql = "insert into users values('%s','%s','%s','%s','%s')" % (username,password,email,dob,mf)
#if the insert was successful
if db.execute(sql):
return redirect('/')
return render_template('signup.html', title='Sign Up', form=form)
Editing Account
Firstly, we will need to create a new form:
class EditAccountForm(FlaskForm):
username = HiddenField('Username', validators=[DataRequired()])
email = StringField('Email', validators=[])
DOB = DateField('DOB', format='%Y-%m-%d')
MF = SelectField('Gender', choices=[('M','Male'), ('F','Female')])
submit = SubmitField('Sign In')
You will need to make the 'username' a hidden field, because you don't want anyone to change the value it contains. I have also not included the 'password' or 'confirm' because this should probably be a more secure process.
Now duplicate the 'signup.html' template and edit it to the following:
{% extends "layout.html" %}
{% block content %}
<h1>Edit Account</h1>
<form action="" method="post" novalidate>
{{ form.hidden_tag() }}
<p>
{{ form.username.label }}<br>
{{ current_user.id }}
</p>
<p>
{{ form.email.label }}<br>
{{ form.email(size=32) }}
</p>
<p>
{{ form.DOB.label }}<br>
{{ form.DOB(size=32) }}
</p>
<p>
{{ form.MF.label }}<br>
{{ form.MF()}}
</p>
<p>{{ form.submit() }}</p>
</form>
{% endblock %}
Now create a new route called 'editaccount':
@app.route('/editaccount', methods=['GET', 'POST'])
@login_required
def editaccount():
form = EditAccountForm()
if request.method == 'POST':
print('check data and submit')
else:
print('get data from db and add to form')
This will be the base for the 'editaccount' route. If the method is set to 'POST' then the form already has data, and in this case we need to check and update the database. The else should be where we add the data to the form to show the current users account details. Now to get the data from the database replace the second print command with:
db = Database()
sql ="select * from users where UserID='%s'" % (current_user.id)
rows=db.select(sql)
if len(rows)!=0:
for row in rows:
form.username.data = row[0]
form.email.data = row[2]
form.DOB.data = datetime.strptime(row[3], '%Y-%m-%d').date()
form.MF.data=row[4]
return render_template('edit.html', title='Edit Account', form=form)
return redirect('/')
This creates a database connection and then gets the data for the current user. You will need to add 'current_user' to the 'flask_login' import line. You will also need to import 'datetime'. The code above checks to see if data has been returned, and then uses a for loop to set each value into the form. The 'DOB' requires the date stored to be converted from a string to a date.
At this point you should be able to login, and then add 'editaccount' to the url.