fastapi 使用依赖注入 dependency-injector

文章目录

  • fastapi 使用依赖注入 dependency-injector
    • 简介
    • 集成 fastapi
      • 依赖
      • 目录结构
      • settings
      • src/api
        • src/api/users
      • src/database
      • src/init_server
      • main.py
    • 启动

fastapi 使用依赖注入 dependency-injector

简介

依赖注入与控制翻转
项目地址:
	https://github.com/ets-labs/python-dependency-injector

集成 fastapi

依赖

dependency-injector==4.41.0
fastapi==0.95.0
uvicorn==0.21.1
SQLAlchemy==2.0.9

目录结构

fastapi 使用依赖注入 dependency-injector_第1张图片

settings

__init__.py

import os

PROJECT_ENV = os.environ.get("PROJECT_ENV", "beta")

if PROJECT_ENV == "online":
    from .online import *
else:
    from .beta import *


class Settings(BaseSettings):
    db_conf: DBConfig = DBConfig()

beta.py

from pydantic import BaseSettings, Field


class DBConfig(BaseSettings):
    url: str = Field(env="aws_ac",default="sqlite:///./webapp.db")

online.py

from pydantic import BaseSettings, Field


class DBConfig(BaseSettings):
    url: str = Field(env="sqlite:///./webapp.db")

src/api

ApplicationModule.py

from dependency_injector import containers, providers

from src.api.users.module import UserModule
# from settings import Settings
# from src.database.db import Database


class Application(containers.DeclarativeContainer):
    # config = providers.Configuration(pydantic_settings=[Settings()])
    # db = providers.Singleton(Database, db_url=config.db_conf.url)

    userModule = providers.Container(
        UserModule,
    )

src/api/users

entities/user.py

from sqlalchemy import Column, String, Boolean, Integer

from src.database.db import Base


class User(Base):

    __tablename__ = "users"

    id = Column(Integer, primary_key=True)
    email = Column(String, unique=True)
    hashed_password = Column(String)
    is_active = Column(Boolean, default=True)

    def __repr__(self):
        return f"{self.id}, " \
               f"email=\"{self.email}\", " \
               f"hashed_password=\"{self.hashed_password}\", " \
               f"is_active={self.is_active})>"

controller.py

from fastapi import APIRouter, Depends

from dependency_injector.wiring import Provide, inject

from src.api.users.module import UserModule
from src.api.users.service import UserService

router = APIRouter()


@router.get("/users")
@inject
def main(
        user_service: UserService = Depends(Provide[UserModule.user_service]),
) :
    user = user_service.get_all_user()
    return user

dao.py

from contextlib import AbstractContextManager
from typing import Iterator, Callable

from sqlalchemy.orm import Session

from src.api.users.entities.user import User


class UserDao:
    def __init__(self, session_factory: Callable[..., AbstractContextManager[Session]]) -> None:
        self.session_factory = session_factory

    # def get_user_all(self):
    #     # self.db.get().all
    #     return {"User": 123}

    def get_user_all(self) -> Iterator[User]:
        with self.session_factory() as session:
            return session.query(User).all()

module.py

from dependency_injector import containers, providers

from settings import Settings
from src.api.users.dao import UserDao
from src.api.users.serializer import UserSerializer
from src.api.users.service import UserService
from src.database.db import Database


class UserModule(containers.DeclarativeContainer):

    # config = providers.Configuration(yaml_files=["config.yml"]) # 使用yml文件作为配置
    config = providers.Configuration(pydantic_settings=[Settings()])

    db = providers.Singleton(Database, db_url=config.db_conf.url)
    wiring_config = containers.WiringConfiguration(modules=["src.api.users.controller"])

    user_dao = providers.Factory(UserDao, session_factory=db.provided.session)
    user_serial = providers.Singleton(UserSerializer)

    user_service = providers.Factory(UserService, user_dao=user_dao, user_serial=user_serial)


serializer.py

class UserSerializer:
    def serial_user_all_data(self, data):
        print("Data: ", data)
        return [
            {
                "user": 1
            },
            {
                "user": 2
            },
            {
                "user": 3
            }
        ]

service.py

from src.api.users.dao import UserDao
from src.api.users.serializer import UserSerializer


class UserService:

    def __init__(self, user_dao: UserDao, user_serial: UserSerializer):
        self.user_dao = user_dao
        self.user_serial = user_serial

    def get_all_user(self):
        return self.user_serial.serial_user_all_data(self.user_dao.get_user_all())

src/database

db

from contextlib import contextmanager, AbstractContextManager
from typing import Callable
import logging

from sqlalchemy import create_engine, orm
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session

logger = logging.getLogger(__name__)

Base = declarative_base()


class Database:

    def __init__(self, db_url: str) -> None:
        print("db_url: ", db_url)
        self._engine = create_engine(db_url, echo=True)
        self._session_factory = orm.scoped_session(
            orm.sessionmaker(
                autocommit=False,
                autoflush=False,
                bind=self._engine,
            ),
        )

    def create_database(self) -> None:
        Base.metadata.create_all(self._engine)

    @contextmanager
    def session(self) -> Callable[..., AbstractContextManager[Session]]:
        session: Session = self._session_factory()
        try:
            print("生成 db session ...........")
            yield session
        except Exception:
            logger.exception("Session rollback because of exception")
            session.rollback()
            raise
        finally:
            print("关闭 这个 session ................")
            session.close()

src/init_server

from src.api.ApplicationModule import Application


def init_di(app):

    container = Application()
    # db = container.db()
    # db.create_database()
    container.wire(modules=[__name__])
    app.container = container
    return app

main.py

import uvicorn
from fastapi import FastAPI

from src.init_server.ioc import init_di
from src.api.users.controller import router


def create_app() -> FastAPI:
    app = FastAPI()

    init_di(app)

    app.include_router(router)
    return app


app = create_app()

if __name__ == '__main__':
    uvicorn.run("main:app", host="0.0.0.0", port=8000)

启动

python main.py 即可

很是优雅 [doge]
这只是一个简单的web应用demo, 具体的使用还需要继续优化.

你可能感兴趣的:(fastapi,数据库,sqlite)