RealWorld: aiohttp, Tortoise ORM
- понедельник, 10 февраля 2020 г. в 00:24:02
На Real World отсутствует пример для aiohttp, и я решил его сделать. Опытным разработчикам, похоже, некогда этим заниматься, а начинающим в aiohttp непонятно как делать правильно. Я начал его делать с помощью Tortoise ORM. Пока начал делать аутентификацию.
Хочется сделать этот проект правильно, поэтому под катом очень много вопросов опытным aiohttp разработчкам.
Склонируйте репозиторий:
git clone git@github.com:nomhoi/aiohttp-realworld-example-app.git
При разработке я использовал Python 3.8. Установите зависимости:
pip install -r requirements.txt
Инициализируем базу данных:
python init_db.py
Запускаем сервер:
python -m conduit
В репозитории присутствует Postman коллекция RealWorld.postman_collection.json. Импортируйте ее в Postman и можете попробовать получившийся API.
По умолчанию используется база данных SQLite.
Для использования PostrgeSQL нужно изменить переменную DB_URL в /conduit/settings.py.
DB_URL = "postgres://postgres:postgres@0.0.0.0:5432/postgres"
Запустить сервис базы данных:
docker-compose up -d
После этого инициализировать базу данных:
python init_db.py
Структура проекта выполнена в соответствии с современным подходом принятым в Django: все приложения находятся на том же уровне что и папка проекта. Это позволяет повторно использовать созданные приложения без их изменения в других проектах.
Аутентификация, профили и статьи будут выполнены в виде отдельных приложений, как и в примере RealWorld для Django.
Папка проекта — conduit.
POST /api/users — регистрация пользователя
POST /api/users/login — аутентификация пользователя
GET /api/user — получение данных текущего пользователя
Обработчики этих запросов находятся в /authentication/views.py.
Использована библиотека aiohttp_cors.
# Configure default CORS settings.
cors = aiohttp_cors.setup(app, defaults={
"*": aiohttp_cors.ResourceOptions(
allow_credentials=True,
expose_headers="*",
allow_headers="*",
)
})
# Configure CORS on all routes.
for route in list(app.router.routes()):
cors.add(route)
Как видим, все включено и разрешено для всех ориджинов, и выполнена общая настройка для всех роутов.
Здесь можете подсказать, как лучше настроить.
Используется aiohttp_jwt:
app = web.Application(
middlewares=[
JWTMiddleware(
settings.SECRET_KEY,
whitelist=[
r'/api/users',
]
)
]
)
JWT работает, только в заголовке Authorizstion вместо Token ставится слово Bearer. В примере для Django — Token. Будет ли работать нормально с фронтэндами пока не проверял.
Используется Tortoise ORM
class TimestampedMixin:
created_at = fields.DatetimeField(auto_now_add=True)
updated_at = fields.DatetimeField(auto_now=True)
class AbstractBaseModel(Model):
id = fields.IntField(pk=True)
class Meta:
abstract = True
class User(TimestampedMixin, AbstractBaseModel):
username = fields.CharField(db_index=True, max_length=255, unique=True)
email = fields.CharField(db_index=True, max_length=255, unique=True)
password = fields.CharField(max_length=128)
class Meta:
table = "user"
def __str__(self):
return self.username
Пока не нашел, как сделать сортировку как в Django примере:
ordering = ['-created_at', '-updated_at']
Думаю, что лучше всего вычисление токена из вьюхи переместить в модель User. Оформить его в виде свойства.
Хранение паролей планирую выполнить как в Django: хэш + соль с алгоритмом PBKDF2. Пока не выполнено.
У Tortoise ORM отсутствуют автоматические миграции. По условиям задачи такое требование отсутствует, поэтому реализовывать не буду.
Пока сделал без сериализаторов. Нашел такой проект, но там старая версия Tortoise ORM.
Существуют и другие реализации сериализаторов. Наверное, с ними разработка ведется идиоматичнее и быстрее. Надо попробовать. ORM прицепили, теперь надо и сериализаторы добавить. А может и рендеров еще добавить?
Пока не добавил. По условиям задачи тесты можно сделать, но они не обязательны.
Нужно еще добавить поддержку профилей, статей и еще много чего. Приглашаются к проекту все желающие прославить свое имя на века и тысячелетия. Приветствуются подсказки и замечания опытных разработчиков.