Hogyan lehet gyors és aszinkron kódot készíteni a Python és a Sanic használatával

Helló mindenki. Ebben a cikkben egyszerű aszinkron projektek építéséről fogok beszélni a Sanic keretrendszerrel.

Bevezetés

Sanicegy nagyon lombikszerű nyílt forráskódú Python webszerver és webkeretrendszer, több mint 10K csillaggal, amelyek gyorsan megírhatók. Lehetővé teszi a async/awaitPython 3.5-ben (további információ) hozzáadott szintaxis használatát , ami a kódot nem blokkolja és gyorsítja.

A Sanic dokumentációja nagyon jó, és a közösség kezeli a közösség számára.

A projekt célja, hogy egyszerű módot kínáljon egy rendkívül teljesítő HTTP szerver üzembe helyezésére, amely könnyen felépíthető, bővíthető és végső soron méretezhető.

Követelmények

Mielőtt elkezdenénk, telepítsünk néhány csomagot, és győződjünk meg arról, hogy minden készen áll a projekt fejlesztésére.

Megjegyzés: A forráskód elérhető a github.com adattáramban. Minden lépéshez tartozik egy megfelelő elkötelezettség.

Előfeltételek:

  • Python3.6 +
  • pipenv (bármely más csomag telepítőt használhat)
  • PostgreSQL(adatbázis esetén lehet MySQL vagy SQLite is)

Csomagok:

  • a secure egy könnyű csomag, amely opcionális biztonsági fejléceket és cookie-attribútumokat ad hozzá a Python webkeretekhez.
  • Az environs egy Python könyvtár a környezeti változók elemzéséhez. Ez lehetővé teszi, hogy a konfigurációt a kódtól külön tárolja, a The Twelve-Factor App módszertanának megfelelően.
  • A sanic-envconfig egy kiterjesztés, amely segít parancssori és környezeti változókat bevinni a Sanic konfigurációjába.
  • Az adatbázisok egy Python csomag, amely lehetővé teszi, hogy lekérdezéseket tegyen az erős SQLAlchemy Core kifejezésnyelv használatával, és támogatást nyújt a PostgreSQL, a MySQL és az SQLite számára.

Hozzunk létre egy üres könyvtárat, és inicializáljunk egy üreset Pipfile.

pipenv  -- python python3.6

Telepítse az összes szükséges csomagot az alábbi pipenv parancsok használatával .

pipenv install sanic secure environs sanic-envconfig

Adatbázis esetén:

pipenv install databases[postgresql]

A választási lehetőségek igenpostgresql, mysql, sqlite.

Szerkezet

Most hozzunk létre néhány fájlt és mappát, ahova beírjuk a tényleges kódunkat.

├── .env├── Pipfile├── Pipfile.lock├── setup.py└── project ├── __init__.py ├── __main__.py ├── main.py ├── middlewares.py ├── routes.py ├── settings.py └── tables.py

A setup.pyfájlt arra használjuk , hogy a projectmappa csomagként elérhető legyen a kódunkban.

from setuptools import setupsetup( name="project",)

Telepítés…

pipenv install -e .

A .envfájlban néhány globális változót, például az adatbázis-kapcsolat URL-jét tároljuk.

__main__.pyúgy van létrehozva, hogy projectcsomagunkat parancssorból futtathatóvá tegyük .

pipenv run python -m project

Inicializálás

Hajtsuk végre az első hívást a __main__.py fájlban.

from project.main import initinit()

Ez az alkalmazásunk kezdete. Most létre kell hoznunk a initfüggvényt a main.py fájl belsejében .

from sanic import Sanicapp = Sanic(__name__)def init(): app.run(host='0.0.0.0', port=8000, debug=True)

Egyszerűen létrehozva az alkalmazást a Sanic osztályból, futtathatjuk azt, megadva a gazdagép , a port és az opcionális hibakeresési kulcsszó argumentumot.

Futás…

pipenv run python -m project

Így kell kinéznie egy sikeres kimenetnek a Sanic alkalmazásban. Ha megnyitja a //0.0.0.0:8000 fájlt a böngészőjében, látni fogja

Hiba: kért URL / nem található

Még nem hoztunk létre útvonalakat , így egyelőre rendben van. Az alábbiakban felsorolunk néhány útvonalat.

Beállítások

Most módosíthatjuk a környezetet és a beállításokat. Hozzá kell adnunk néhány változót az .env fájlba, el kell olvasnunk és át kell mennünk a Sanic alkalmazás konfigurációjába.

.env fájl.

DEBUG=TrueHOST=0.0.0.0POST=8000

Konfiguráció…

from sanic import Sanic
from environs import Envfrom 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 fájl.

from sanic_envconfig import EnvConfigclass Settings(EnvConfig): DEBUG: bool = True HOST: str = '0.0.0.0' PORT: int = 8000

Felhívjuk figyelmét, hogy felvettem egy opcionális auto_reload argumentumot, amely be- vagy kikapcsolja az Automatikus újratöltőt.

Adatbázis

Itt az ideje, hogy beállítson egy adatbázist.

Egy kis megjegyzés az adatbázis- csomagról, mielőtt továbblépnénk:

adatbázisok csomag asyncpg-t használ amely aszinkron interfészkönyvtár a PostgreSQL számára. Elég gyors. Lásd az eredményeket alább.

A Sanic két hallgatóját fogjuk használni, ahol meghatározzuk az adatbázis-összekapcsolási és -bontási műveleteket. Itt vannak a hallgatók, amelyeket használni fogunk:

  • after_server_start
  • after_server_stop

main.py file.

from sanic import Sanic
from databases import Database
from environs import Envfrom 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, )

Once more thing. We need to specify DB_URL in project settings and environment.

.env file.

DEBUG=TrueHOST=0.0.0.0POST=8000DB_URL=postgresql://postgres:[email protected]/postgres

And settings.py file.

from sanic_envconfig import EnvConfigclass Settings(EnvConfig): DEBUG: bool = True HOST: str = '0.0.0.0' PORT: int = 8000 DB_URL: str = ''

Make sure that DB_URL is correct and your database is running. Now you can access to database using app.db. See more detailed information in the next section.

Tables

Now we have a connection to our database and we can try to do some SQL queries.

Let’s declare a table in tables.py file using SQLAlchemy.

import sqlalchemymetadata = 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)),)

Here I assume that you already have a migrated database with a books table in it. For creating database migrations, I recommend that you use Alembic which is a lightweight and easy-to-use tool that you can use with the SQLAlchemy Database Toolkit for Python.

Now we can use any SQLAlchemy core queries. Check out some examples below.

# Executing manyquery = 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 rowsquery = books.select()rows = await app.db.fetch_all(query)# Fetch single rowquery = books.select()row = await app.db.fetch_one(query)

Routes

Now we need to setup routes. Let’s go to routes.py and add a new route for 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] })

Of course we need to call setup_routes in init to make it work.

from project.routes import setup_routes
app = Sanic(__name__)
def init(): ... app.config.from_object(Settings) setup_database() setup_routes(app) ...

Requesting…

$ curl localhost:8000/books{"books":[{"No Highway":"Nevil Shute"},{"The Daffodil":"SkyH. E. Bates"}]}

Middlewares

What about checking the response headers and seeing what we can add or fix there?

$ curl -I localhost:8000Connection: keep-aliveKeep-Alive: 5Content-Length: 32Content-Type: text/plain; charset=utf-8

As you can see we need some security improvements. There are some missing headers such as X-XSS-Protection, Strict-Transport-Securityso let’s take care of them using a combination of middlewares and secure packages.

middlewares.py file.

from secure import SecureHeaderssecure_headers = SecureHeaders()def setup_middlewares(app): @app.middleware('response') async def set_secure_headers(request, response): secure_headers.sanic(response)

Setting up middlewares in main.py file.

from project.middlewares import setup_middlewares
app = Sanic(__name__)
def init(): ... app.config.from_object(Settings) setup_database() setup_routes(app) setup_middlewares(app) ...

The result is:

$ curl -I localhost:8000/booksConnection: keep-aliveKeep-Alive: 5Strict-Transport-Security: max-age=63072000; includeSubdomainsX-Frame-Options: SAMEORIGINX-XSS-Protection: 1; mode=blockX-Content-Type-Options: nosniffReferrer-Policy: no-referrer, strict-origin-when-cross-originPragma: no-cacheExpires: 0Cache-control: no-cache, no-store, must-revalidate, max-age=0Content-Length: 32Content-Type: text/plain; charset=utf-8

As I promised at the beginning, there is a github repository for each section in this article. Hope this small tutorial helped you to get started with Sanic. There are still many unexplored features in the Sanic framework that you can find and check out in the documentation.

davitovmasyan/sanic-project

Goin' Fast and asynchronous with Python and Sanic! - davitovmasyan/sanic-projectgithub.com

If you have thoughts on this, be sure to leave a comment.

If you found this article helpful, give me some claps ?

Thanks for reading. Go Fast with Sanic and good luck!!!