create account

Part 5 - Creating a web application with Flask - Redirecting and logging in by amosbastian

View this thread on: hive.blogpeakd.comecency.com
· @amosbastian · (edited)
$17.21
Part 5 - Creating a web application with Flask - Redirecting and logging in
<center>https://cdn.discordapp.com/attachments/404587860872921088/407939181751304194/steempy_flask.png
</center>


<center><sup>Thanks to @oups for the image!</sup></center>

I've recently created [my own web application using Flask](https://github.com/amosbastian/PMTC) and had some trouble with a few things, so once I figured them out, I thought I might as well make a tutorial series so others don't have to run into the same problems as myself! In this tutorial we will go through how to redirect a user to a different page, how to create and handle a login form and see if a user exists in your database.

---

#### What will I learn
- How to redirect a user
- How to create a login form
- How to handle a login form
- How to see if a user exists in your database

#### Requirements

- Python2 or Python3.3+

#### Difficulty

- Intermediate

---

### Tutorial
If you find it easier to follow along this way you can get the entire code for this tutorial from [here](https://github.com/amosbastian/flask-tutorial/tree/part5), where I have split everything up into the relevant sections.

#### Redirecting a user
Once a user has registered we should redirect them to the login page. Doing this is really easy, we can simply use the `redirect()` and `url_for` functions! After importing them from `flask` we can simply uncomment the code at the end of the `register()` function we created in `app.py`. The way this works is that instead of rendering a given template, it simply directs the user to the URL for a given template, which is pretty similar. Of course this will currently give us an error as we haven't created a template or route for `login` yet, so let's do that now!

#### Creating a login form and route in `app.py`
First things first, let's create the form and route needed for our login template! Just like how we created our `RegistrationForm` in part 4, we can do the same and create a `LoginForm` instead. In this form we only need the user's name and the user's password. For now let's create a simple one where we just require something to be entered, with some placeholders like Steemit uses

```
class LoginForm(FlaskForm):
    name = StringField("Name", validators=[DataRequired()],
        render_kw={"placeholder": "Enter your username"})
    password = PasswordField("Password", validators=[DataRequired()],
        render_kw={"placeholder": "Password or WIF"})
```

Now we have our form we should create a route to our template. Once again we can use the same code as for the registration template, so I won't explain everything again

```
@app.route("/login", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        pass
        # HANDLE FORM
    return render_template("login.html", form=form)
```
#### Creating our login template

Before we think about handling the form's data we need to actually create our template first. This is very easy since we can once again reuse the code from `registration.html`, but without the password confirmation field! Let's also change it from a `form-group` class to an `input-group` class so we can prepend the `@` sign just like Steemit does on the login page!

```
{% extends "layout.html" %}

{% block body %}
<h2>Returning Users: Login</h2>
<form method="POST" action="{{ url_for('login') }}" class="form-horizontal">
    {{ form.csrf_token }}
    <div class="input-group mb-3">
        <div class="input-group-prepend">
            <span class="input-group-text" id="basic-addon1">@</span>
        </div>
        {{ form.name(class_="form-control") }}
    </div>
    {% for error in form.name.errors %}
    <div class="alert alert-danger" role="alert">
        {{ error }}
    </div>
    {% endfor %}

    <div class="input-group mb-3">
        {{ form.password(class_="form-control") }}
    </div>
    {% for error in form.password.errors %}
    <div class="alert alert-danger" role="alert">
        {{ error }}
    </div>
    {% endfor %}

    <p><input type="submit" name="Submit" class="btn btn-outline-primary"></p>
</form>
{% endblock %}
```
As you can see in the picture below it's already looking pretty nice (with input validation working)! The next step is actually handling the data that the user enters!

<center>![login_validation.png](https://steemitimages.com/DQmWXaPuzvn9kSM497wHgfmzjV3cvNLL891frE451NN1ZDL/login_validation.png)</center>

#### Handling the form
So now we've created the form in both `app.py` and `login.html` we need a way to actually handle it. This time instead of inserting the data into a database, we want to check if the user is already in the database or not. To do this we need to extract the data from the form, create a cursor and execute a command to see if the user is already in the database. First of all let's see if we can find the user in the database and just print a confirmation to the terminal for now. The way to do this is pretty similar to inserting a user in the database, as you will see in the code below

```
@app.route("/login", methods=["GET", "POST"])
def login():
    form = LoginForm()
    if form.validate_on_submit():
        # Get data from the form
        name = form.name.data
        password = form.password.data

        # Create a cursor
        cursor = mysql.connection.cursor()

        # Execute command to find user in database
        result = cursor.execute("SELECT * FROM users WHERE name = %s", [name])

        # If user exists
        if result == 1:
            print("Found user {}!".format(name))
        # If user doesn't exist
        else:
            print("Couldn't find user {}!".format(name))
    return render_template("login.html", form=form)
```
As you can see we simply extract the data from the form, create a cursor and execute a command to find any users with the given name. If the user exists then the result should equal 1 and we print ""Found user `name`!", otherwise we print "Couldn't find user `name`!". Let's run `app.py` and see if this works!
  
<center>![database_test.png](https://steemitimages.com/DQmSkZerZq9EX4oamnyWXNcKrPYATe91ZTEbNYvnX5uoTiG/database_test.png)</center>

#### Adding errors and comparing passwords

So we can now see if a user exists in our database, but we don't actually use the password for anything yet. Let's change that! To do this we can use our cursor to fetch the user's password and then use `passwordlib` to compare the two and see if they match. We should also give the user some feedback, because currently they don't know what's happening. We can do this by passing an error to our template, like how we pass our form to the template!

```
# If user exists
if result == 1:

    # Fetch the user and password
    user = cursor.fetchone()
    fetched_password = user["password"]

    # If passwords match
    if sha512_crypt.verify(password, fetched_password):
        pass
    # If passwords don't match
    else:
        error = "Invalid password!"
        return render_template("login.html", form=form, error=error)
# If user doesn't exist
else:
    error = "User does not exist!"
    return render_template("login.html", form=form, error=error)
```
To show the error in `login.html` we can just add an *if* statement above our form with a `div` showing the error, like so

```
{% if error %}
<div class="alert alert-danger" role="alert">
    {{ error }}
</div>
{% endif %}
```

Let's run `app.py` once again and see if it works! Indeed, it shows an error when entering an invalid password or username!

<center>![invalid_password.png](https://steemitimages.com/DQmNMYkWBcgupBpGGYHv9ndiMoquh4y5Usp3C9XzfMpQqWW/invalid_password.png)</center>


**Congratulations**, you've now learned how to redirect a user to a different page, how to create and handle a login form and see if a user exists in your database.

### Curriculum
- [Part 1 - Creating a web application with Flask - Initial setup and routes](https://utopian.io/utopian-io/@amosbastian/part-1-creating-a-web-application-with-flask-initial-setup-and-routes)
- [Part 2 - Creating a web application with Flask - Including and extending templates](https://utopian.io/utopian-io/@amosbastian/part-2-creating-a-web-application-with-flask-including-and-extending-templates)
- [Part 3 - Creating a web application with Flask - For loops, creating a database and forms](https://utopian.io/utopian-io/@amosbastian/part-3-creating-a-web-application-with-flask-for-loops-creating-a-database-and-forms)
- [Part 4 - Creating a web application with Flask - Handling form data](https://utopian.io/utopian-io/@amosbastian/part-4-creating-a-web-application-with-flask-handling-form-data)

---

The code for this tutorial can be found on [GitHub](https://github.com/amosbastian/flask-tutorial/tree/part5)!

In the next tutorial we will find out how to store information about a user, how to hide and show content depending on if a user is logged in or not, how to log a user out and how to restrict a user's access.

<br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@amosbastian/part-5-creating-a-web-application-with-flask-redirecting-and-logging-in">Utopian.io -  Rewarding Open Source Contributors</a></em><hr/>
👍  , , , , , , , , , , , , , , , , ,
properties (23)
authoramosbastian
permlinkpart-5-creating-a-web-application-with-flask-redirecting-and-logging-in
categoryutopian-io
json_metadata{"community":"utopian","app":"utopian/1.0.0","format":"markdown","repository":{"id":596892,"name":"flask","full_name":"pallets/flask","html_url":"https://github.com/pallets/flask","fork":false,"owner":{"login":"pallets"}},"pullRequests":[],"platform":"github","type":"tutorials","tags":["utopian-io","python","flask","tutorial","programming"],"users":["oups"],"links":["https://github.com/amosbastian/PMTC","https://github.com/amosbastian/flask-tutorial/tree/part5","https://utopian.io/utopian-io/@amosbastian/part-1-creating-a-web-application-with-flask-initial-setup-and-routes","https://utopian.io/utopian-io/@amosbastian/part-2-creating-a-web-application-with-flask-including-and-extending-templates","https://utopian.io/utopian-io/@amosbastian/part-3-creating-a-web-application-with-flask-for-loops-creating-a-database-and-forms","https://utopian.io/utopian-io/@amosbastian/part-4-creating-a-web-application-with-flask-handling-form-data","https://utopian.io/utopian-io/@amosbastian/part-5-creating-a-web-application-with-flask-redirecting-and-logging-in"],"image":["https://cdn.discordapp.com/attachments/404587860872921088/407939181751304194/steempy_flask.png","https://steemitimages.com/DQmWXaPuzvn9kSM497wHgfmzjV3cvNLL891frE451NN1ZDL/login_validation.png","https://steemitimages.com/DQmSkZerZq9EX4oamnyWXNcKrPYATe91ZTEbNYvnX5uoTiG/database_test.png","https://steemitimages.com/DQmNMYkWBcgupBpGGYHv9ndiMoquh4y5Usp3C9XzfMpQqWW/invalid_password.png"],"moderator":{"account":"ewq","time":"2018-02-04T05:43:53.907Z","reviewed":true,"pending":false,"flagged":false}}
created2018-02-03 12:15:27
last_update2018-02-04 05:43:54
depth0
children4
last_payout2018-02-10 12:15:27
cashout_time1969-12-31 23:59:59
total_payout_value12.742 HBD
curator_payout_value4.470 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length9,145
author_reputation174,473,586,900,705
root_title"Part 5 - Creating a web application with Flask - Redirecting and logging in"
beneficiaries
0.
accountutopian.pay
weight2,500
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id34,630,390
net_rshares3,225,593,243,363
author_curate_reward""
vote details (18)
@ewq ·
$0.10
Thank you for the contribution. It has been approved.

You can contact us on [Discord](https://discord.gg/uTyJkNm).
**[[utopian-moderator]](https://utopian.io/moderators)**
👍  
properties (23)
authorewq
permlinkre-amosbastian-part-5-creating-a-web-application-with-flask-redirecting-and-logging-in-20180204t054400929z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2018-02-04 05:44:00
last_update2018-02-04 05:44:00
depth1
children1
last_payout2018-02-11 05:44:00
cashout_time1969-12-31 23:59:59
total_payout_value0.076 HBD
curator_payout_value0.023 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length172
author_reputation2,798,579,990,254
root_title"Part 5 - Creating a web application with Flask - Redirecting and logging in"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id34,810,642
net_rshares15,297,158,679
author_curate_reward""
vote details (1)
@amosbastian ·
Thanks!
properties (22)
authoramosbastian
permlinkre-ewq-re-amosbastian-part-5-creating-a-web-application-with-flask-redirecting-and-logging-in-20180204t132115493z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"app":"steemit/0.1"}
created2018-02-04 13:21:15
last_update2018-02-04 13:21:15
depth2
children0
last_payout2018-02-11 13:21:15
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length7
author_reputation174,473,586,900,705
root_title"Part 5 - Creating a web application with Flask - Redirecting and logging in"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id34,886,593
net_rshares0
@steemitstats ·
@amosbastian, Upvote is the only thing I can support you.
properties (22)
authorsteemitstats
permlink20180203t121549174z-post
categoryutopian-io
json_metadata{"tags":["utopian-io"]}
created2018-02-03 12:15:33
last_update2018-02-03 12:15:33
depth1
children0
last_payout2018-02-10 12:15:33
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length57
author_reputation351,882,871,185
root_title"Part 5 - Creating a web application with Flask - Redirecting and logging in"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id34,630,408
net_rshares0
@utopian-io ·
### Hey @amosbastian I am @utopian-io. I have just upvoted you!
#### Achievements
- You have less than 500 followers. Just gave you a gift to help you succeed!
- Seems like you contribute quite often. AMAZING!
#### Suggestions
- Contribute more often to get higher and higher rewards. I wish to see you often!
- Work on your followers to increase the votes/rewards. I follow what humans do and my vote is mainly based on that. Good luck!
#### Get Noticed!
- Did you know project owners can manually vote with their own voting power or by voting power delegated to their projects? Ask the project owner to review your contributions!
#### Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. <a href="https://discord.gg/zTrEMqB">Participate on Discord</a>. Lets GROW TOGETHER!
- <a href="https://v2.steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1">Vote for my Witness With SteemConnect</a>
- <a href="https://v2.steemconnect.com/sign/account-witness-proxy?proxy=utopian-io&approve=1">Proxy vote to Utopian Witness with SteemConnect</a>
- Or vote/proxy on <a href="https://steemit.com/~witnesses">Steemit Witnesses</a>

[![mooncryption-utopian-witness-gif](https://steemitimages.com/DQmYPUuQRptAqNBCQRwQjKWAqWU3zJkL3RXVUtEKVury8up/mooncryption-s-utopian-io-witness-gif.gif)](https://steemit.com/~witnesses)

**Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x**
properties (22)
authorutopian-io
permlinkre-amosbastian-part-5-creating-a-web-application-with-flask-redirecting-and-logging-in-20180204t192433633z
categoryutopian-io
json_metadata{"tags":["utopian-io"],"community":"utopian","app":"utopian/1.0.0"}
created2018-02-04 19:24:33
last_update2018-02-04 19:24:33
depth1
children0
last_payout2018-02-11 19:24:33
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length1,509
author_reputation152,955,367,999,756
root_title"Part 5 - Creating a web application with Flask - Redirecting and logging in"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id34,960,459
net_rshares0