Register and Edit profile in a Flask App

From TRCCompSci - AQA Computer Science
Jump to: navigation, search

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 in your 'forms.py':

class EditAccountForm(FlaskForm):
    username = HiddenField('Username', validators=[DataRequired()])
    email = StringField('Email', validators=[Email()])
    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. You will also need to add 'HiddenField' to the 'wtforms' import line.

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]
                if rows[3] != "":
                    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. This will show you the current details for that user.

Now for updating the database if the user clicks the submit button, replace the first print statement above with the following:

        if form.validate_on_submit():
            username = form.username.data
            email = form.email.data
            dob = form.DOB.data
            mf = form.MF.data
            db = Database()
            sql = "update users set UserEmail='%s' , UserDOB='%s', UserMF='%s' where UserID='%s'" % (email,dob,mf,username)                      
            if db.execute(sql):
                return redirect('/')
        return render_template('edit.html', title='Edit Account', form=form)

This code will first check if the data entered into the form is valid (only email has validators at the moment). It then grabs the data entered from the form, creates a database connection and then executes an update SQL query. If the update was successful it redirects to the root page, and any other error will render the template again with the data entered.