- •ВВЕДЕНИЕ
- •1. ПОДГОТОВКА К РАЗРАБОТКЕ
- •1.1. НАЧАЛО РАБОТЫ
- •1.2. ИСПОЛЬЗОВАНИЕ КОНТЕЙНЕРОВ DOCKER
- •1.3. НАСТРОЙКА СУБД POSTGRESQL
- •1.4. НАСТРОЙКА ТЕСТОВ
- •1.6. СОЗДАНИЕ RESTFUL-МАРШРУТОВ
- •1.6.1. МАРШРУТ POST /USERS
- •1.6.3. МАРШРУТ GET /USERS
- •1.6.2. МАРШРУТ GET /USERS/:ID
- •1.7. ИСПОЛЬЗОВАНИЕ ШАБЛОНОВ JINJA
- •1.8. СТРУКТУРА ПРОЕКТА
- •2. ОТЛАДКА ПРИЛОЖЕНИЯ
- •2.1. ПОКРЫТИЕ ТЕСТАМИ И КАЧЕСТВО КОДА
- •2.1.1. ПОКРЫТИЕ КОДА ТЕСТАМИ
- •2.1.2. КАЧЕСТВО КОДА
- •2.2. НЕПРЕРЫВНАЯ ИНТЕГРАЦИЯ
- •2.3. ПАНЕЛЬ ИНСТРУМЕНТОВ ОТЛАДКИ FLASK
- •2.4. СТРУКТУРА ПРИЛОЖЕНИЯ
- •3. РАЗВИТИЕ ПРИЛОЖЕНИЯ
- •3.1. ПАКЕТ FLASK MIGRATE
- •3.1.1. ИЗМЕНЕНИЕ МОДЕЛИ
- •3.1.2. НАСТРОЙКА FLASK MIGRATE
- •3.2. РЕФАКТОРИНГ КОДА
- •3.3. ПАКЕТ FLASK BCRYPT
- •3.4. НАСТРОЙКА LOG ROUNDS
- •3.5. ИСПОЛЬЗОВАНИЕ ТОКЕНОВ JWT
- •3.5.1. ПАКЕТ PYJWT
- •3.5.2. РАСШИФРОВКА ТОКЕНА
- •3.6. МАРШРУТЫ ДЛЯ АУТЕНТИФИКАЦИИ
- •3.6.1. МАРШРУТ POST /AUTH/REGISTER
- •3.6.2. МАРШРУТ POST /AUTH/LOGIN
- •3.6.3. МАРШРУТ GET /AUTH/LOGOUT
- •3.6.4. МАРШРУТ GET /AUTH/STATUS
- •ЗАКЛЮЧЕНИЕ
- •СПИСОК ЛИТЕРАТУРЫ
{
"data": { "users": [ ]
},
"status": "success"
}
Добавим функцию в файл manage.py, чтобы заполнить базу данных на-
чальными данными:
@cli.command()
def seed_db():
""" Заполняет базу данных."""
db.session.add(User(username='testname1',
email="testname1@gmail.com"))
db.session.add(User(
username='testname3',
email="testname3@flaskapp.com"))
db.session.commit()
Попробуем выполнить следующую команду:
$ docker-compose -f docker-compose-dev.yml
\ run users python manage.py seed_db
Убедимся, что можно получать информацию о пользователях в ответе
JSON, используя маршрут http://DOCKER_MACHINE_IP:5001/users.
Подумайте, как можно уменьшить объём некоторых тестов с помощью одного и того же кода. Постарайтесь не жертвовать удобочитаемостью, если всё же решите провести рефакторинг.
1.7. ИСПОЛЬЗОВАНИЕ ШАБЛОНОВ JINJA
Вместо того, чтобы просто использовать JSON API, добавим в приложе-
ние возможность использовать шаблоны на стороне сервера.
Добавим новый обработчик маршрута в файл services/users/project/api/ users.py:
@users_blueprint.route('/', methods=['GET'])
def index():
return render_template('index.html')
Также обновим конфигурацию Blueprint:
users_blueprint = Blueprint('users', __name__, tem-
plate_folder='./templates')
28
При этом необходимо обязательно обновить и импорт:
from flask import Blueprint, jsonify, request, render_template
Затем добавим каталог templates в project/api и разместим в этом каталоге
файл index.html следующего содержания:
<!DOCTYPE html> <html>
<head>
<meta charset="utf-8"> <title>Flask on Docker</title> <!-- meta -->
<meta name="description" content=""> <meta name="author" content="">
<meta name="viewport" content="width=device-width,initial- scale=1"> <!-- styles -->
<link
href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.
css"
rel="stylesheet"
>
{% block css %}{% endblock %} </head>
<body>
<div class="container"> <div class="row">
<div class="col-md-4"> <br> <h1>All Users</h1> <hr><br>
<form action="/" method="POST"> <div class="form-group">
<input
name="username" class="form-control input-lg" type="text" placeholder="Enter a username" required>
</div>
<div class="form-group"> <input
name="email" class="form-control input-lg"
type="email" placeholder="Enter an email address" required> </div>
<input
type="submit" class="btn btn-primary btn-lg btn-block"
29
value="Submit">
</form>
<br> <hr>
{% if users %} <ol>
{% for user in users %} <li>{{user.username}}</li> {% endfor %}
</ol>
{% else %}
<p>No users!</p>
{% endif %} </div>
</div>
</div>
</div>
<!-- scripts --> <script
type="text/javascript" src="//code.jquery.com/jquery-2.2.4.min.js" ></script>
<script
type="text/javascript"
src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js " >
</script>
{% block js %}{% endblock %} </body>
</html>
Переходим к тестированию. Необходимо открыть браузер и перейти на
IP-адрес, связанный с контейнером testdriven-dev.
Напишем тест:
def test_main_no_users(self):
"""Проверка, что основной маршрут ведёт себя корректно, когда в базу данных не добавлены пользователи."""
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
self.assertIn(b'<h1>All Users</h1>', response.data)
self.assertIn(b'<p>No users!</p>', response.data)
Проверим, выполняется ли тест:
$ docker-compose -f docker-compose-dev.yml \
run users python manage.py test
30
Обновим обработчик маршрута, чтобы получить данные всех пользовате-
лей из базы данных и отправить их в шаблон. Начнём с написания теста:
def test_main_with_users(self):
"""Проверка, что основной маршрут ведет себя корректно, когда
пользователи были добавлены в базу данных."""
add_user('testname1', 'testname1@flaskapp.org')
add_user('testname2', 'testname2@flaskapp.com')
with self.client:
response = self.client.get('/')
self.assertEqual(response.status_code, 200)
self.assertIn(b'<h1>All Users</h1>', response.data)
self.assertNotIn(b'<p>No users!</p>', response.data)
self.assertIn(b'testname1', response.data)
self.assertIn(b'testname2', response.data)
Убедимся, что тест не работает, а затем обновим функцию-представле-
ние:
@users_blueprint.route('/', methods=['GET'])
def index():
users = User.query.all()
return render_template('index.html', users=users)
Теперь тест должен успешно выполниться.
Пользователи должны иметь возможность добавить нового пользователя,
отправив на сервер форму, которая затем добавит пользователя в базу данных.
Снова начнём с написания теста:
def test_main_add_user(self):
"""Проверка, что в базу данных можно добавить нового пользовате-
ля."""
with self.client:
response = self.client.post( '/',
data=dict(username='testname1',
email='testname1@soflaskapp.com'), \ follow_redirects=True)
self.assertEqual(response.status_code, 200)
self.assertIn(b'<h1>All Users</h1>', response.data)
self.assertNotIn(b'<p>No users!</p>', response.data)
self.assertIn(b'testname1', response.data)
Затем обновим функцию представления:
@users_blueprint.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
31
