FastAPI(64)- Settings and Environment Variables 配置项和环境变量


FastAPI(64)- Settings and Environment Variables 配置项和环境变量 

  • 在许多情况下,应用程序可能需要一些外部设置或配置,例如密钥、数据库凭据、电子邮件服务凭据等。
  • 大多数这些设置都是可变的(可以更改),例如数据库 URL,很多可能是敏感数据,比如密码
  • 出于这个原因,通常在应用程序读取的环境变量中提供它们

Pydantic Settings
#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠萝测试笔记
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/10/9 7:25 下午
# file: 52_settings_env.py
"""
import os

import uvicorn
from fastapi import FastAPI
from pydantic import BaseSettings


class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50


settings = Settings()
app = FastAPI()


@app.get("/info")
async def info():
    return {
        "app_name": settings.app_name,
        "admin_email": settings.admin_email,
        "items_per_user": settings.items_per_user,
    }
  • 然后,当创建 Settings 该类的实例时Pydantic 将以不区分大小写的方式读取环境变量
  • 因此,仍会为属性 app_name 读取为大写变量 APP_NAME
  • 接下来它将转换和验证数据
  • 因此,当使用该 settings 对象时,将拥有声明的类型的数据(例如 items_per_user 是 int)

 

运行 uvicorn 服务器
ADMIN_EMAIL="deadpool@example.com" APP_NAME="ChimichangApp" uvicorn main:app

访问 /info 接口

config.py 
from pydantic import BaseSettings

class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50

settings = Settings()

 

main.py
from fastapi import FastAPI
from .config import settings


app = FastAPI()


@app.get("/info")
async def info():
    return {
        "app_name": settings.app_name,
        "admin_email": settings.admin_email,
        "items_per_user": settings.items_per_user,
    }

Settings 在依赖项中

  • 在某些情况下,提供依赖项的 Settings 会有用,而不是让全局对象拥有可随处使用的 Settings
  • 在测试期间会有用,因为使用自定义 Settings 覆盖依赖项非常容易

config.py 
from pydantic import BaseSettings

class Settings(BaseSettings):
    app_name: str = "Awesome API"
    admin_email: str
    items_per_user: int = 50

这里不创建默认实例 settings = Settings()

main.py
from fastapi import FastAPI, Depends
from functools import lru_cache
from .config import Settings

app = FastAPI()

@lru_cache
def get_settings():
    return Settings


@app.get("/info")
async def info(settings: Settings = Depends(get_settings)):
    return {
        "app_name": settings.app_name,
        "admin_email": settings.admin_email,
        "items_per_user": settings.items_per_user,
    }

测试上述接口
from fastapi.testclient import TestClient
from .config import Settings
from .main import app, get_settings

client = TestClient(app)

# 依赖覆盖,为 Settings 对象设置一个新的 admin_email 值
def get_settings_override():
    return Settings(admin_email="testing_admin@example.com")

app.dependency_overrides[get_settings] = get_settings_override


def test_app():
    response = client.get("/info")
    data = response.json()
    assert data == {
        "app_name": "Awesome API",
        "admin_email": "testing_admin@example.com",
        "items_per_user": 50,
    }

命令行执行
> pytest 53_settings_test.py                                                      
============================================================================================================ test session starts ============================================================================================================
platform darwin -- Python 3.9.5, pytest-6.2.5, py-1.10.0, pluggy-1.0.0
rootdir: /Users/polo/Downloads/FastAPI_project
plugins: anyio-3.3.2
collected 1 item                                                                                                                                                                                                                            

53_settings_test.py .                                                                                                                                                                                                                 [100%]

============================================================================================================= 1 passed in 0.30s =============================================================================================================

使用 .env 文件

如果有会经常变化的设置项,也许在不同的环境中,将它们放在一个文件中,然后从文件中读取它们,就好像它们是环境变量一样

这些环境变量通常放在一个文件 .env 中,该文件称为“dotenv”

tips

背景
def get_settings():
    return Settings()

上述代码,如果作为请求的依赖项,那么每次请求进来,都会创建一个 Settings 对象,然后读取一次 .env 文件,这不是我们希望的

@lru_cache
from functools import lru_cache
from fastapi import Depends, FastAPI
from . import config

app = FastAPI()


@lru_cache()
def get_settings():
    return config.Settings()


@app.get("/info")
async def info(settings: config.Settings = Depends(get_settings)):
    return {
        "app_name": settings.app_name,
        "admin_email": settings.admin_email,
        "items_per_user": settings.items_per_user,
    }

对于后续请求的依赖项中的 get_settings() 的任何后续调用,它不会执行 get_settings() 的内部代码并创建新的 Settings 对象,而是返回与第一次调用时返回的相同对象

lru_cache 技术细节

  

 

 
  • 本文作者: 小菠萝测试笔记
  • 本文链接: