- •ВВЕДЕНИЕ
- •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
- •ЗАКЛЮЧЕНИЕ
- •СПИСОК ЛИТЕРАТУРЫ
3.РАЗВИТИЕ ПРИЛОЖЕНИЯ
Втретьей части мы добавим миграции базы данных вместе с функцией хеширования паролей для реализации аутентификации на основе токенов для сервиса, отвечающего за регистрацию пользователей с помощью веб-токенов
JSON (JSON Web Tokens, JWT).
3.1.ПАКЕТ FLASK MIGRATE
Вэтом параграфе мы используем библиотеку Flask Migrate для обработки миграций базы данных.
Установим среду testdriven-dev в качестве активной для Docker Machine:
$ docker-machine env testdriven-dev
$ eval $(docker-machine env testdriven-dev)
Обновим контейнеры:
$ docker-compose -f docker-compose-dev.yml up -d
Убедимся, что приложение работает в браузере, а затем запустим тесты:
$ docker-compose -f docker-compose-dev.yml \ run users python manage.py test
$ docker-compose -f docker-compose-dev.yml \ run client npm test
3.1.1. ИЗМЕНЕНИЕ МОДЕЛИ
Внесём несколько изменений в схему в services/users/project/api/ models.py.
1.Поле username в модели должно быть уникальным.
2.Поле email в модели должно быть уникальным.
Также добавим поле password (в следующем параграфе), которое будет хешировано перед добавлением в базу данных:
password = db.Column(db.String(255), nullable=False)
Пока не вносите никаких изменений. Начнём с тестов. Добавим новый файл в services/users/project/tests с именем test_user_model.py. Этот файл будет содержать тесты, связанные с моделью базы данных:
import unittest
40
from project import db
from project.api.models import User
from project.tests.base import BaseTestCase
class TestUserModel(BaseTestCase):
def test_add_user(self): user = User(
username='justatest',
email='test@test.com',
)
db.session.add(user)
db.session.commit()
self.assertTrue(user.id) self.assertEqual(user.username, 'justatest') self.assertEqual(user.email, 'test@test.com') self.assertTrue(user.active)
def test_add_user_duplicate_username(self): user = User(
username='justatest',
email='test@test.com',
)
db.session.add(user)
db.session.commit() duplicate_user = User(
username='justatest',
email='test@test2.com',
)
db.session.add(duplicate_user) self.assertRaises(IntegrityError, db.session.commit)
def test_add_user_duplicate_email(self): user = User(
username='justatest',
email='test@test.com',
)
db.session.add(user)
db.session.commit()
41
duplicate_user = User( username='justanothertest', email='test@test.com', )
db.session.add(duplicate_user) self.assertRaises(IntegrityError, db.session.commit)
def test_to_json(self): user = User(
username='justatest',
email='test@test.com',
)
db.session.add(user)
db.session.commit() self.assertTrue(isinstance(user.to_json(), dict))
if __name__ == '__main__': unittest.main()
Обратите внимание, что мы не вызывали метод db.session.commit() во второй раз при добавлении пользователя. Вместо этого мы передали и db.session.commit в метод assertRaises() и позволили методу assertRaises() вызы-
вать его и произвести появление исключения.
Не стоит забывать, что вместо этого можно использовать assertRaises в
качестве менеджера контекста:
with self.assertRaises(IntegrityError):
db.session.commit()
Добавим импорт:
from sqlalchemy.exc import IntegrityError
Запустим тесты. Вы должны увидеть сообщения о двух ошибках:
test_add_user_duplicate_email (test_user_model.TestUserModel) ...
FAIL test_add_user_duplicate_username (test_user_model.TestUserModel) ... FAIL
Сама ошибка:
NameError: name 'add_user' is not defined
AssertionError: IntegrityError not raised by do
AssertionError: IntegrityError not raised by do
42
3.1.2. НАСТРОЙКА FLASK MIGRATE
Поскольку нужно изменить схему базы данных, добавим Flask-Migrate в
файл requirements.txt:
flask-migrate==2.1.1
В файл services/users/project/__init__.py добавим импорт, создадим новый
экземпляр и обновим функцию create_app():
# services/users/project/__init__.py
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_debugtoolbar import DebugToolbarExtension from flask_cors import CORS
from flask_migrate import Migrate
# инстанционирование расширений db = SQLAlchemy()
toolbar = DebugToolbarExtension() migrate = Migrate()
def create_app(script_info=None):
# инстанционирование приложения app = Flask(__name__)
#включение CORS CORS(app)
#подключение конфигурации
app_settings = os.getenv('APP_SETTINGS') app.config.from_object(app_settings)
# запуск расширений db.init_app(app) toolbar.init_app(app) migrate.init_app(app, db)
43
# регистрация blueprints
from project.api.users import users_blueprint app.register_blueprint(users_blueprint)
# контекст оболочки для flask cli app.shell_context_processor({'app': app, 'db': db}) return app
Прежде чем создавать миграции, обновим файл .dockerignore:
env
htmlcov
.dockerignore
Dockerfile-dev
Dockerfile-prod
migrations
Затем обновим контейнеры:
$ docker-compose -f docker-compose-dev.yml up -d --build
Создадим каталог миграции, добавим начальную миграцию, а затем при-
меним её к базе данных:
$ docker-compose -f docker-compose-dev.yml \ run users python manage.py db init
$ docker-compose -f docker-compose-dev.yml
\run users python manage.py db migrate $ docker-compose -f docker-compose-dev.yml
\run users python manage.py db upgrade
Теперь мы можем внести изменения в схему:
class User(db.Model): __tablename__ = "users"
id = db.Column(db.Integer, primary_key=True, autoincrement=True) username = db.Column(db.String(128), unique=True, nullable=False) email = db.Column(db.String(128), unique=True, nullable=False) active = db.Column(db.Boolean, default=True, nullable=False)
Снова выполним команды:
$ docker-compose -f docker-compose-dev.yml
\run users python manage.py db migrate $ docker-compose -f docker-compose-dev.yml
\run users python manage.py db upgrade
44
