[Python, Программирование] Как сделать ваш код на Python быстрым и асинхронным с Sanic (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
В преддверии старта курса "Python Developer. Professional" подготовили традиционный перевод полезной статьи.
Всем привет, в этой статье я расскажу о создании простых асинхронных проектов на фреймворке Sanic.ВведениеSanic– это очень похожий на Flask открытый веб-сервер и веб-фреймворк на Python с более чем 10К звездами, который быстро развивается. Он позволяет использовать синтаксис async/await, который был добавлен в Python 3.5, помогая делать ваш код неблокирующим и быстрым.У Sanic очень хорошая документация, которая пишется членами сообщества для самого сообщества.
Цель проекта – предложить простой способ запуска высокопроизводительного HTTP-сервера, который легко создавать, расширять и в конечном итоге масштабировать.
ТребованияПеред тем, как начать, давайте установим несколько пакетов и убедимся, что у нас есть все необходимое для создания проекта.Примечание: Исходный код есть на моем github. Каждый шаг отражен в отдельном коммите. Предустановки
- Python3.6+
- pipenv (или любой другой установщик пакетов)
- PostgreSQL (для баз данных, можно также взять MySQL или SQLite)
Пакеты
- secure – это легкий пакет, который добавляет заголовки безопасности и атрибуты файлов cookie для веб-фреймворков Python.
- environs – библиотека Python для синтаксического анализа переменных окружения. Она позволяет хранить конфигурацию отдельно от кода, в соответствии с методологией приложения двенадцати факторов.
- sanic-envconfig – это расширение, которое помогает вам переносить командную строку и переменные окружения в вашу конфигурацию Sanic.
- databases – это пакет Python, который позволяет создавать запросы с использованием мощного языка выражений SQLAlchemy Core и обеспечивает поддержку PostgreSQL, MySQL и SQLite.
Давайте создадим пустой каталог и инициализируем пустой Pipfile.
pipenv -- python python3.6
Установите все необходимые пакеты, используя приведенные ниже команды pipenv.
pipenv install sanic secure environs sanic-envconfig
Для базы данных:
pipenv install databases[postgresql]
На выбор postgresql, mysql, sqlite.СтруктураТеперь давайте создадим несколько файлов и папок, где мы будем писать код.
├── .env
├── Pipfile
├── Pipfile.lock
├── setup.py
└── project
├── __init__.py
├── __main__.py
├── main.py
├── middlewares.py
├── routes.py
├── settings.py
└── tables.py
Мы будем использовать файл setup.py, чтобы сделать папку project доступной как пакет в нашем коде.
from setuptools import setup
setup(
name='project',
)
Установка…
pipenv install -e .
В файле .env мы будем хранить глобальные переменные, такие как строку подключения к базе данных. _main_.py создан для того, чтобы наш пакет project мог выполняться из командной строки.
pipenv run python -m project
ИнициализацияДавайте сделаем первый вызов в файле main.py
from project.main import init
init()
Это начало нашего приложения. Теперь нам нужно создать функцию init в файле main.py.
from sanic import Sanic
app = Sanic(__name__)
def init():
app.run(host='0.0.0.0', port=8000, debug=True)
Просто создав app из класса Sanic, мы можем запустить его, указав хост, порт и необязательный аргумент с ключевым словом debug.Запускаем…
pipenv run python -m project
Sanic console outputПри успешном запуске приложения Sanic вывод будет выглядеть именно так. Если в браузере вы откроете http://0.0.0.0:8000, то увидите:
Error: Requested URL / not found
Мы еще не создали никаких маршрутов, так что все в порядке. Мы займемся этим дальше.НастройкаТеперь мы можем модифицировать среду и настройки. Нам нужно добавить некоторые переменные в файл .env, прочитать их и передать в файл конфигурации приложения Sanic.Файл .env
DEBUG=True
HOST=0.0.0.0
POST=8000
Конфигурация…
from sanic import Sanic
from environs import Env
from project.settings import Settings
app = Sanic(__name__)
def init():
env = Env()
env.read_env()
app.config.from_object(Settings)
app.run(
host=app.config.HOST,
port=app.config.PORT,
debug=app.config.DEBUG,
auto_reload=app.config.DEBUG,
)
Файл settings.py
from sanic_envconfig import EnvConfig
class Settings(EnvConfig):
DEBUG: bool = True
HOST: str = '0.0.0.0'
PORT: int = 8000
Обратите внимание, что я добавил необязательный аргумент auto_reload, который активирует или деактивирует автоматическую перезагрузку.База данныхСейчас самое время настроить базу данных.Одно замечание о базе данных прежде, чем мы пойдем дальше. Пакет databases использует asyncpg, который является асинхронным интерфейсом библиотеки для работы с PostgreSQL. Работает достаточно быстро. Результаты вы можете посмотреть ниже.
Мы будем использовать двух слушателей Sanic, для которых укажем операции подключения и отключения от базы данных. Вот слушатели, которых мы будем использовать:
- afterserverstart
- afterserverstop
Файл main.py
from sanic import Sanic
from databases import Database
from environs import Env
from project.settings import Settings
app = Sanic(__name__)
def setup_database():
app.db = Database(app.config.DB_URL)
@app.listener('after_server_start')
async def connect_to_db(*args, **kwargs):
await app.db.connect()
@app.listener('after_server_stop')
async def disconnect_from_db(*args, **kwargs):
await app.db.disconnect()
def init():
env = Env()
env.read_env()
app.config.from_object(Settings)
setup_database()
app.run(
host=app.config.HOST,
port=app.config.PORT,
debug=app.config.DEBUG,
auto_reload=app.config.DEBUG,
)
И еще кое-что. Нам нужно указать DB_URL в настройках проекта и среде.Файл .env
DEBUG=True
HOST=0.0.0.0
POST=8000
DB_URL=postgresql://postgres:postgres@localhost/postgres
И файл settings.py:
from sanic_envconfig import EnvConfig
class Settings(EnvConfig):
DEBUG: bool = True
HOST: str = '0.0.0.0'
PORT: int = 8000
DB_URL: str = ''
Убедитесь, что DB_URL верный и ваша база данных запущена. Теперь вы можете получить доступ к базе данных с помощью app.db. Более подробную информацию можно получить в следующем разделе.ТаблицыТеперь у нас есть подключение к нашей базе данных, и мы можем попробовать сделать несколько SQL-запросов.Давайте объявим таблицу в файле tables.py с помощью SQLAlchemy.
import sqlalchemy
metadata = sqlalchemy.MetaData()
books = sqlalchemy.Table(
'books',
metadata,
sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column('title', sqlalchemy.String(length=100)),
sqlalchemy.Column('author', sqlalchemy.String(length=60)),
)
Сейчас я предполагаю, что вы уже сделали миграцию базы данных с таблицей books в ней. Для создания миграций баз данных я рекомендую использовать Alembic – легкий и простой инструмент, который можно использовать вместе с инструментарием базы данных SQLAlchemy для Python.Теперь мы можем использовать любые запросы SQLAlchemy. Ниже представлены несколько примеров.
# Executing many
query = books.insert()
values = [
{"title": "No Highway", "author": "Nevil Shute"},
{"title": "The Daffodil", "author": "SkyH. E. Bates"},
]
await app.db.execute_many(query, values)
# Fetching multiple rows
query = books.select()
rows = await app.db.fetch_all(query)
# Fetch single row
query = books.select()
row = await app.db.fetch_one(query)
МаршрутыТеперь нам нужно настроить маршруты. Давайте перейдем в routes.py и добавим новый маршрут для books.
from sanic.response import json
from project.tables import books
def setup_routes(app):
@app.route("/books")
async def book_list(request):
query = books.select()
rows = await request.app.db.fetch_all(query)
return json({
'books': [{row['title']: row['author']} for row in rows]
})
Конечно же, чтобы все работало, нам нужно в init вызвать setup_routes.
from project.routes import setup_routes
app = Sanic(__name__)
def init():
...
app.config.from_object(Settings)
setup_database()
setup_routes(app)
...
Делаем запрос…
$ curl localhost:8000/books
{"books":[{"No Highway":"Nevil Shute"},{"The Daffodil":"SkyH. E. Bates"}]}
MiddlewareМожет проверим заголовки ответов и посмотрим, можем ли мы добавить или исправить там что-нибудь?
$ curl -I localhost:8000
Connection: keep-alive
Keep-Alive: 5
Content-Length: 32
Content-Type: text/plain; charset=utf-8
Как видите, в вопросах безопасности нам есть что улучшить. Есть несколько пропущенных заголовков, таких как X-XSS-Protection, Strict-Transport-Security и т.д. Поэтому давайте разберемся с ними с помощью дополнительного ПО и пакетов secure.Файл middlewares.py
from secure import SecureHeaders
secure_headers = SecureHeaders()
def setup_middlewares(app):
@app.middleware('response')
async def set_secure_headers(request, response):
secure_headers.sanic(response)
Настройка middleware в файле main.py:
from project.middlewares import setup_middlewares
app = Sanic(__name__)
def init():
...
app.config.from_object(Settings)
setup_database()
setup_routes(app)
setup_middlewares(app)
...
А вот и результат:
$ curl -I localhost:8000/books
Connection: keep-alive
Keep-Alive: 5
Strict-Transport-Security: max-age=63072000; includeSubdomains
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer, strict-origin-when-cross-origin
Pragma: no-cache
Expires: 0
Cache-control: no-cache, no-store, must-revalidate, max-age=0
Content-Length: 32
Content-Type: text/plain; charset=utf-8
Как я и обещал в самом начале, для каждого раздела этой статьи есть отдельный репозиторий на github. Надеюсь, этот небольшой туториал поможет вам начать работу с Sanic. В фреймворке Sanic есть еще много неисследованных функций, с ними вы можете познакомиться в документации.
===========
Источник:
habr.com
===========
===========
Автор оригинала: Davit Tovmasyan
===========Похожие новости:
- [PHP, Программирование, Java] Финальные классы в PHP, Java и других языках (перевод)
- [Разработка мобильных приложений, Разработка под Android, Разработка под MacOS, Разработка под Linux, Разработка под Windows] Разработка мобильных приложений на Python. Создание анимаций в Kivy. Part 2
- [Разработка игр, Тестирование игр] Тестирование игр
- [Python, Программирование] Itertools в Python (перевод)
- [Программирование, Go] JSON с опциональными полями в Go (перевод)
- [Программирование, Разработка под iOS, Облачные сервисы] Интеграция CI/CD для нескольких сред с Jenkins и Fastlane. Часть 3 (перевод)
- [Ненормальное программирование, Разработка веб-сайтов, Python, Программирование] iPad для разработчика
- [Программирование, .NET, Разработка под MacOS] Поддержка процессоров Apple M1 в .NET
- [Программирование, Java, Apache, Промышленное программирование] Spring Boot app with Apache Kafka in Docker container (перевод)
- [CMS, PHP, Программирование, Разработка под e-commerce, Интернет-маркетинг] Генератор ocmod-файла для интернет-магазина на Opencart
Теги для поиска: #_python, #_programmirovanie (Программирование), #_python, #_sanic, #_blog_kompanii_otus._onlajnobrazovanie (
Блог компании OTUS. Онлайн-образование
), #_python, #_programmirovanie (
Программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:05
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
В преддверии старта курса "Python Developer. Professional" подготовили традиционный перевод полезной статьи.
Цель проекта – предложить простой способ запуска высокопроизводительного HTTP-сервера, который легко создавать, расширять и в конечном итоге масштабировать.
pipenv -- python python3.6
pipenv install sanic secure environs sanic-envconfig
pipenv install databases[postgresql]
├── .env
├── Pipfile ├── Pipfile.lock ├── setup.py └── project ├── __init__.py ├── __main__.py ├── main.py ├── middlewares.py ├── routes.py ├── settings.py └── tables.py from setuptools import setup
setup( name='project', ) pipenv install -e .
pipenv run python -m project
from project.main import init
init() from sanic import Sanic
app = Sanic(__name__) def init(): app.run(host='0.0.0.0', port=8000, debug=True) pipenv run python -m project
Sanic console outputПри успешном запуске приложения Sanic вывод будет выглядеть именно так. Если в браузере вы откроете http://0.0.0.0:8000, то увидите: Error: Requested URL / not found
DEBUG=True
HOST=0.0.0.0 POST=8000 from sanic import Sanic
from environs import Env from project.settings import Settings app = Sanic(__name__) def init(): env = Env() env.read_env() app.config.from_object(Settings) app.run( host=app.config.HOST, port=app.config.PORT, debug=app.config.DEBUG, auto_reload=app.config.DEBUG, ) from sanic_envconfig import EnvConfig
class Settings(EnvConfig): DEBUG: bool = True HOST: str = '0.0.0.0' PORT: int = 8000 Мы будем использовать двух слушателей Sanic, для которых укажем операции подключения и отключения от базы данных. Вот слушатели, которых мы будем использовать:
from sanic import Sanic
from databases import Database from environs import Env from project.settings import Settings app = Sanic(__name__) def setup_database(): app.db = Database(app.config.DB_URL) @app.listener('after_server_start') async def connect_to_db(*args, **kwargs): await app.db.connect() @app.listener('after_server_stop') async def disconnect_from_db(*args, **kwargs): await app.db.disconnect() def init(): env = Env() env.read_env() app.config.from_object(Settings) setup_database() app.run( host=app.config.HOST, port=app.config.PORT, debug=app.config.DEBUG, auto_reload=app.config.DEBUG, ) DEBUG=True
HOST=0.0.0.0 POST=8000 DB_URL=postgresql://postgres:postgres@localhost/postgres from sanic_envconfig import EnvConfig
class Settings(EnvConfig): DEBUG: bool = True HOST: str = '0.0.0.0' PORT: int = 8000 DB_URL: str = '' import sqlalchemy
metadata = sqlalchemy.MetaData() books = sqlalchemy.Table( 'books', metadata, sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True), sqlalchemy.Column('title', sqlalchemy.String(length=100)), sqlalchemy.Column('author', sqlalchemy.String(length=60)), ) # Executing many
query = books.insert() values = [ {"title": "No Highway", "author": "Nevil Shute"}, {"title": "The Daffodil", "author": "SkyH. E. Bates"}, ] await app.db.execute_many(query, values) # Fetching multiple rows query = books.select() rows = await app.db.fetch_all(query) # Fetch single row query = books.select() row = await app.db.fetch_one(query) from sanic.response import json
from project.tables import books def setup_routes(app): @app.route("/books") async def book_list(request): query = books.select() rows = await request.app.db.fetch_all(query) return json({ 'books': [{row['title']: row['author']} for row in rows] }) from project.routes import setup_routes
app = Sanic(__name__) def init(): ... app.config.from_object(Settings) setup_database() setup_routes(app) ... $ curl localhost:8000/books
{"books":[{"No Highway":"Nevil Shute"},{"The Daffodil":"SkyH. E. Bates"}]} $ curl -I localhost:8000
Connection: keep-alive Keep-Alive: 5 Content-Length: 32 Content-Type: text/plain; charset=utf-8 from secure import SecureHeaders
secure_headers = SecureHeaders() def setup_middlewares(app): @app.middleware('response') async def set_secure_headers(request, response): secure_headers.sanic(response) from project.middlewares import setup_middlewares
app = Sanic(__name__) def init(): ... app.config.from_object(Settings) setup_database() setup_routes(app) setup_middlewares(app) ... $ curl -I localhost:8000/books
Connection: keep-alive Keep-Alive: 5 Strict-Transport-Security: max-age=63072000; includeSubdomains X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff Referrer-Policy: no-referrer, strict-origin-when-cross-origin Pragma: no-cache Expires: 0 Cache-control: no-cache, no-store, must-revalidate, max-age=0 Content-Length: 32 Content-Type: text/plain; charset=utf-8 =========== Источник: habr.com =========== =========== Автор оригинала: Davit Tovmasyan ===========Похожие новости:
Блог компании OTUS. Онлайн-образование ), #_python, #_programmirovanie ( Программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 13:05
Часовой пояс: UTC + 5