Истории успеха наших клиентов — лучшие проекты
Вход/ Регистрация

Создание веб-приложения с использованием Python Flask

9790
15 минут чтения
Средний рейтинг статьи: 2.1

В предыдущей статье в блоге Timeweb Cloud мы познакомились с веб-разработкой на python с использованием Flask и рассмотрели способы работы с входящими данными. В этом туториале мы шагнем чуть дальше и напишем простое веб-приложение на python с базой данных для авторизации пользователей.

Мы будем работать в PyCharm+pipenv, а сайт сделаем на HTML+CSS. Операционная система — Win 10. Установка Flask, PyCharm и pipenv подробно описана в этой статье.

Создание Веб Приложения С Использованием Python Flask (2)

В рамках статьи мы будем использовать тестовые, учебные примеры, которые не подойдут для реализации на продакшене. Например,  для проверки пароля в БД необходимо хранить хэш пароля и сравнивать хэши, а не пароли. Также для работы с СУБД нужно использовать ORM, а не писать «сырой» SQL (подробнее про ORM см. здесь).

Кстати, в официальном канале Timeweb Cloud собрали комьюнити из специалистов, которые говорят про IT-тренды, делятся полезными инструкциями и даже приглашают к себе работать.

Для начала работы создадим директорию проекта — Timeweb. В ней разместим директории templates и static, а в директории static создадим директорию css. Теперь структура проекта выглядит так:

    
Timeweb |— templates |— static |    — css

БД для логинов и паролей

После того, как вы установите Flask и остальные инструменты, можно перейти к работе. Для хранения данных пользователей будем использовать СУБД SQlite. Она отлично подходит для небольших проектов. Её основное преимущество заключается в автономности: для работы с ней не потребуется сервер. К тому же в python встроен модуль sqlite3 для работы с ней. Но если вы решите работать с СУБД на сервере, то обратите внимание на облачные серверы Timeweb Cloud.

В директории проекта создаем файл db.py. В файле импортируем модуль sqlite3 и создаем базу данных и таблицу с логинами и паролями:

    
import sqlite3
    
db_lp = sqlite3.connect('login_password.db') cursor_db = db_lp.cursor() sql_create = '''CREATE TABLE passwords( login TEXT PRIMARY KEY, password TEXT NOT NULL);''' cursor_db.execute(sql_create) db_lp.commit() cursor_db.close() db_lp.close()

Распишем подробно, что этот код делает:

  • Подключаемся к БД с помощью метода connect(). Метод будет искать файл login_password.db в каталоге проекта. Если не найдет, то создаст самостоятельно.
  • Создаем объект cursor_db для взаимодействия с БД;
  • sql_create — это SQL-запрос для создания таблицы с логинами и паролями;
  • С помощью метода execute() выполняем sql_create;
  • Сохраняем изменения в БД методом commit();
  • Закрываем объекты cursor_db и db_lp во избежание проблем с БД.

Для создания базы данных выполняем команду:

    
python db.py

Авторизация

Основная форма

Сначала создадим форму, с помощью которой будет осуществляться авторизация в абстрактный сервис.

В директории templates создаем файл authorization.html с содержанием:

    
<form method="POST">   <div class="container">     <label for="Login"><b>Логин</b></label>     <input type="text" placeholder="" name="Login" required>     <label for="Password"><b>Пароль</b></label>     <input type="password" placeholder="" name="Password" required>     <button type="submit">Войти</button>    <div class="container">     <span class="reg"> <a href="/registration">Регистрация</a></span>   </div> </form>   <link rel="stylesheet" href="{{ url_for('static', filename= 'css/auth.css') }}">

  Здесь важно 3 момента:

  • <form method="POST"> — указываем, что будем использовать POST-запросы;
  • label for="Login" и label for="Password" — отмечаем Login, который в дальнейшем будем обрабатывать с помощью метода get() из модуля request;
  • <link rel="stylesheet" href="{{ url_for('static', filename= 'css/auth.css') }}"> — сообщаем HTML, где хранится css-файл.

В директории /static/css создаем файл auth.css:

    
form {     font: 14px Stem-Regular,arial, sans-serif;/*Выбираем шрифт */     border: 1px solid black;/*Цвет, размер и тип границы */     -webkit-border-radius: 20px;/*Скругляем углы */     color: #777991;/*Цвет label */     width: 25%; /*Ширина формы */     margin-right: auto; /*Положение формы */     margin-left: auto; /*Положение формы */     text-align: center; /*Центровка текста*/ } input[type=text], input[type=password] {     text-align: center; /*Центровка текста*/     -webkit-border-radius: 4px;/*Скругляем углы */     width: auto; /*Ширина */     padding: 15px 20px; /*Размер внутренних отступов*/     margin: 10px 0; /*Размер внешних отступов*/     margin-right: auto; /*Размер внешних отступов справа*/     margin-left: auto; /*Размер внешних отступов слева*/     display: block; /*тип отображения*/     border: 1px solid #050c26;/*Цвет, размер и тип границы */     box-sizing: border-box; /*Размер объекта по отношению к родительскому */     font: 14px Stem-Regular,arial, sans-serif;/*Выбираем шрифт */     color: #777991;/*Цвет текста в input */ } button {     font: 16px Stem-medium, arial, sans-serif; /*Выбираем шрифт кнопки */     background-color: #454cee; /*Выбираем цвет фона */     -webkit-border-radius: 8px; /*Закругление */     color: white; /*Выбираем цвет текста*/     padding: 16px 20px; /*Размер внутренних отступов*/     margin: 8px 0;/*Размер внешних отступов*/     border: none; /*Без границы*/     cursor: pointer; /*Изменение курсора при наведении на кнопку*/     width: auto; /*Ширина*/ } button:hover {      opacity: 0.9; /*Изменение яркости кнопки при наведении*/ } .container {     padding: 20px; /*Размер внутренних отступов контейнера*/ }

В итоге наша форма будет выглядеть так:

Image5

Сообщение для успешной авторизации

Если пользователь ввёл верную пару логин-пароль, то выведем соответствующее сообщение.

В директории templates создаем файл successfulauth.html с содержанием:

    
<form method="POST">   <div class="container">     <label><b>Вы успешно авторизовались</b></label>    </form> <link rel="stylesheet" href="{{ url_for('static', filename= 'css/successfulauth.css') }}">

В директории /static/css создаем файл successfulauth.css:

    
form {     font: 14px Stem-Regular,arial, sans-serif;/*Выбираем шрифт */     border: 1px solid black;/*Цвет, размер и тип границы */     -webkit-border-radius: 20px;/*Скругляем углы */     color: #777991;/*Цвет label */     width: 25%; /*Ширина формы */     margin-right: auto; /*Положение формы */     margin-left: auto; /*Положение формы */     text-align: center; /*Центровка текста*/ } .container {     padding: 30px; /*Размер внутренних отступов контейнера*/ }

Image2

Сообщение при неудачной авторизации

В директории templates создаем файл auth_bad.html с содержанием:

    
<form method="POST"> <form method="POST">   <div class="container">     <label><b>Введен неправильный логин или пароль</b></label>    </form>   <link rel="stylesheet" href="{{ url_for('static', filename= 'css/auth_bad.css') }}">

В директории /static/css создаем файл auth_bad.css:

    
form {     font: 14px Stem-Regular,arial, sans-serif;/*Выбираем шрифт */     border: 1px solid black;/*Цвет, размер и тип границы */     -webkit-border-radius: 20px;/*Скругляем углы */     color: #777991;/*Цвет label */     width: 25%; /*Ширина формы */     margin-right: auto; /*Положение формы */     margin-left: auto; /*Положение формы */     text-align: center; /*Центровка текста*/ } .container {     padding: 30px;/*Размер внутренних отступов контейнера*/ }

Image3

Теперь создадим форму для регистрации.

Регистрация

С помощью формы регистрации пользователь сможет создать свой аккаунт. 

В templates создаем файл registration.html:

    
<form method="POST">   <div class="container">     <label for="Login"><b>Логин</b></label>     <input type="text" placeholder="" name="Login" required>     <label for="Password"><b>Пароль</b></label>     <input type="password" placeholder="" name="Password" required>        <button type="submit">Зарегистрироваться</button>   </div> </form>   <link rel="stylesheet" href="{{ url_for('static', filename= 'css/regis.css') }}">

В /static/css создаем regis.css:

    
form {      font: 14px Stem-Regular,arial, sans-serif;/*Выбираем шрифт */     border: 1px solid black;/*Цвет, размер и тип границы */     -webkit-border-radius: 20px;/*Скругляем углы */     color: #777991;/*Цвет label */     width: 25%; /*Ширина формы */     margin-right: auto; /*Положение формы */     margin-left: auto; /*Положение формы */     text-align: center; /*Центровка текста*/ } input[type=text], input[type=password] {     text-align: center; /*Центровка текста*/     -webkit-border-radius: 4px;/*Скругляем углы */     width: auto; /*Ширина */     padding: 15px 20px; /*Размер внутренних отступов*/     margin: 10px 0; /*Размер внешних отступов*/     margin-right: auto; /*Размер внешних отступов справа*/     margin-left: auto; /*Размер внешних отступов слева*/     display: block; /*тип отображения*/     border: 1px solid #050c26;/*Цвет, размер и тип границы */     box-sizing: border-box; /*Размер объекта по отношению к родительскому */     font: 14px Stem-Regular,arial, sans-serif;/*Выбираем шрифт */     color: #777991;/*Цвет текста в input */   } button {     font: 16px Stem-medium, arial, sans-serif; /*Выбираем шрифт кнопки */     background-color: #454cee; /*Выбираем цвет фона */     -webkit-border-radius: 8px; /*Закругление */     color: white; /*Выбираем цвет текста*/     padding: 16px 20px; /*Размер внутренних отступов*/     margin: 8px 0;/*Размер внешних отступов*/     border: none; /*Без границы*/     cursor: pointer; /*Изменение курсора при наведении на кнопку*/     width: auto; /*Ширина*/ } button:hover {      opacity: 0.9; /*Изменение яркости кнопки при наведении*/ } .container {     padding: 20px; /*Размер внутренних отступов контейнера*/ }

Форма регистрации будет выглядть так:

Image1

При завершении регистрации пользователь увидит такое сообщение:

Image4

Для этого в templates создаем файл successfulregis.html:

    
<form method="POST"> <div class="container">     <label><b>Вы успешно зарегистрировались</b></label>        <div class="container">     <span class="reg"> <a href="/authorization">Вернуться к авторизации</a></span>   </div> </form>   <link rel="stylesheet" href="{{ url_for('static', filename= 'css/successfulregis.css') }}">

А в /static/css создаем successfulregis.css:

    
form {     font: 14px Stem-Regular,arial, sans-serif;/*Выбираем шрифт */     border: 1px solid black;/*Цвет, размер и тип границы */     -webkit-border-radius: 20px;/*Скругляем углы */     color: #777991;/*Цвет label */     width: 25%; /*Ширина формы */     margin-right: auto; /*Положение формы */     margin-left: auto; /*Положение формы */     text-align: center; /*Центровка текста*/ } .container {     padding: 20px;/*Размер внутренних отступов контейнера*/ }

Декоратор авторизации

После создания всех форм и БД мы можем начать разработку веб-приложения Flask. Для отправления html-документа в ответ на запрос клиента в Flask нужно использовать метод render_template(). Эта функция модуля Flask используется для отображения шаблонов из папки templates.

Сейчас каталог проекта имеет такую структуру:

    
Timeweb |— db.py |— login_password.db |— templates |     `— authorization.html |     `— auth_bad.html |     `— successfulauth.html |     `— successfulregis.html |     `— registration.html |— static |    — css |         `— auth_bad.css |         `— auth.css |         `— successfulauth.css |         `— regis.css |         `— successfulregis.css

В директории проекта /Timeweb создаем файл main.py, в котором импортируем необходимые модули из Flask и добавляем код для авторизации пользователей. Подробнее об аутентификации рекомендуем почитать здесь.

    
from flask import Flask, request, render_template import sqlite3 @app.route('/authorization', methods=['GET', 'POST']) def form_authorization():    if request.method == 'POST':        Login = request.form.get('Login')        Password = request.form.get('Password')       db_lp = sqlite3.connect('login_password.db')        cursor_db = db_lp.cursor()        cursor_db.execute(('''SELECT password FROM passwords                                                WHERE login = '{}';                                                ''').format(Login))        pas = cursor_db.fetchall()        cursor_db.close()        try:            if pas[0][0] != Password:                return render_template('auth_bad.html')        except:            return render_template('auth_bad.html')        db_lp.close()        return render_template('successfulauth.html')    return render_template('authorization.html')

Вот логика его работы:

  • Пользователь переходит на /authorization — это GET-запрос, и декоратор возвращает authorization.html;
  • Когда пользователь введет логин, пароль и нажмет кнопку «Войти», сервер получит POST-запрос, который декоратор будет обрабатывать. Декоратор получит логин и пароль, которые ввел пользователь;
  • Затем подключаемся к БД и выполняем SQL-запрос к ней. С помощью cursor_db.execute() и cursor_db.fetchall() получаем строку password (возможно, пустую), соответствующую введенному логину;
  • Из строки «вытаскиваем» пароль, и:
    • Если строка пустая, то это вызовет ошибку (выход за пределы массива), которую мы обрабатываем конструкцией try-except и сообщаем пользователю о неверных введенных данных. Декоратор завершает работу;
    • Если пароль в БД не совпадает с полученным паролем, то просто возвращает сообщение о некорректности данных и завершаем работу;
    • Если пароль верный, то выдаем сообщение о успешной авторизации и завершаем работу Flask-декоратора.

Декоратор регистрации

На страницу /registration пользователь попадает из формы авторизации. Вот код декоратора, добавляем его в конец main.py:

    
@app.route('/registration', methods=['GET', 'POST']) def form_registration():    if request.method == 'POST':        Login = request.form.get('Login')        Password = request.form.get('Password')        db_lp = sqlite3.connect('login_password.db')        cursor_db = db_lp.cursor()        sql_insert = '''INSERT INTO passwords VALUES('{}','{}');'''.format(Login, Password)        cursor_db.execute(sql_insert)        db_lp.commit()        cursor_db.close()        db_lp.close()        return render_template('successfulregis.html')    return render_template('registration.html')
  • Сначала обрабатывается GET-запрос /registration. Возвращаем registration.html;
  • Когда пользователь введет данные и нажмет кнопку «Зарегистрироваться», сервер получит POST-запрос. Из него получаем Login и Password;
  • Подключаемся к БД;
  • sql_insert — запрос на добавление новой строки с данными пользователя;
  • Выполняем sql_insert и сохраняем изменения;
  • Закрываем cursor_db, db_lp и возвращаем сообщение об успешной регистрации.

Полный код программы

    
from flask import Flask, request, render_template import sqlite3 app = Flask(__name__) @app.route('/authorization', methods=['GET', 'POST']) def form_authorization():    if request.method == 'POST':        Login = request.form.get('Login')        Password = request.form.get('Password')      db_lp = sqlite3.connect('login_password.db')        cursor_db = db_lp.cursor()        cursor_db.execute(('''SELECT password FROM passwords                                                WHERE login = '{}';                                                ''').format(Login))        pas = cursor_db.fetchall()        cursor_db.close()        try:            if pas[0][0] != Password:                return render_template('auth_bad.html')        except:            return render_template('auth_bad.html')        db_lp.close()        return render_template('successfulauth.html')    return render_template('authorization.html') @app.route('/registration', methods=['GET', 'POST']) def form_registration():    if request.method == 'POST':        Login = request.form.get('Login')        Password = request.form.get('Password')        db_lp = sqlite3.connect('login_password.db')        cursor_db = db_lp.cursor()        sql_insert = '''INSERT INTO passwords VALUES('{}','{}');'''.format(Login, Password)

       cursor_db.execute(sql_insert)

       cursor_db.close()

       db_lp.commit()
       db_lp.close()

       return render_template('successfulregis.html')

   return render_template('registration.html')


if __name__ == "__main__":
 app.run()
9790
15 минут чтения
Средний рейтинг статьи: 2.1
Хотите внести свой вклад?
Участвуйте в нашей контент-программе за
вознаграждение или запросите нужную вам инструкцию
img-server
Пока нет комментариев