Movatterモバイル変換


[0]ホーム

URL:


Saltar a contenido
Join theFastAPI Cloud waiting list 🚀
Follow@fastapi onX (Twitter) to stay updated
FollowFastAPI onLinkedIn to stay updated
Subscribe to theFastAPI and friends newsletter 🎉
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor
sponsor

Configuraciones y Variables de Entorno

🌐 Traducción por IA y humanos

Esta traducción fue hecha por IA guiada por humanos. 🤝

Podría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖

Puedes mejorar esta traducciónayudándonos a guiar mejor al LLM de IA.

Versión en inglés

En muchos casos, tu aplicación podría necesitar algunas configuraciones o ajustes externos, por ejemplo, claves secretas, credenciales de base de datos, credenciales para servicios de correo electrónico, etc.

La mayoría de estas configuraciones son variables (pueden cambiar), como las URLs de bases de datos. Y muchas podrían ser sensibles, como los secretos.

Por esta razón, es común proporcionarlas en variables de entorno que son leídas por la aplicación.

Consejo

Para entender las variables de entorno, puedes leerVariables de Entorno.

Tipos y validación

Estas variables de entorno solo pueden manejar strings de texto, ya que son externas a Python y tienen que ser compatibles con otros programas y el resto del sistema (e incluso con diferentes sistemas operativos, como Linux, Windows, macOS).

Eso significa que cualquier valor leído en Python desde una variable de entorno será unstr, y cualquier conversión a un tipo diferente o cualquier validación tiene que hacerse en código.

PydanticSettings

Afortunadamente, Pydantic proporciona una gran utilidad para manejar estas configuraciones provenientes de variables de entorno conPydantic: Settings management.

Instalarpydantic-settings

Primero, asegúrate de crear tuentorno virtual, actívalo y luego instala el paquetepydantic-settings:

$pipinstallpydantic-settings---> 100%

También viene incluido cuando instalas los extrasall con:

$pipinstall"fastapi[all]"---> 100%

Crear el objetoSettings

ImportaBaseSettings de Pydantic y crea una sub-clase, muy similar a un modelo de Pydantic.

De la misma forma que con los modelos de Pydantic, declaras atributos de clase con anotaciones de tipos, y posiblemente, valores por defecto.

Puedes usar todas las mismas funcionalidades de validación y herramientas que usas para los modelos de Pydantic, como diferentes tipos de datos y validaciones adicionales conField().

fromfastapiimportFastAPIfrompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):app_name:str="Awesome API"admin_email:stritems_per_user:int=50settings=Settings()app=FastAPI()@app.get("/info")asyncdefinfo():return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}

Consejo

Si quieres algo rápido para copiar y pegar, no uses este ejemplo, usa el último más abajo.

Luego, cuando creas un instance de esa claseSettings (en este caso, en el objetosettings), Pydantic leerá las variables de entorno de una manera indiferente a mayúsculas y minúsculas, por lo que una variable en mayúsculasAPP_NAME aún será leída para el atributoapp_name.

Luego convertirá y validará los datos. Así que, cuando uses ese objetosettings, tendrás datos de los tipos que declaraste (por ejemplo,items_per_user será unint).

Usar elsettings

Luego puedes usar el nuevo objetosettings en tu aplicación:

fromfastapiimportFastAPIfrompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):app_name:str="Awesome API"admin_email:stritems_per_user:int=50settings=Settings()app=FastAPI()@app.get("/info")asyncdefinfo():return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}

Ejecutar el servidor

Luego, ejecutarías el servidor pasando las configuraciones como variables de entorno, por ejemplo, podrías establecer unADMIN_EMAIL yAPP_NAME con:

$ADMIN_EMAIL="deadpool@example.com"APP_NAME="ChimichangApp"fastapirunmain.py<span style="color: green;">INFO</span>:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)

Consejo

Para establecer múltiples env vars para un solo comando, simplemente sepáralas con un espacio y ponlas todas antes del comando.

Y luego la configuraciónadmin_email se establecería en"deadpool@example.com".

Elapp_name sería"ChimichangApp".

Y elitems_per_user mantendría su valor por defecto de50.

Configuraciones en otro módulo

Podrías poner esas configuraciones en otro archivo de módulo como viste enAplicaciones Más Grandes - Múltiples Archivos.

Por ejemplo, podrías tener un archivoconfig.py con:

frompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):app_name:str="Awesome API"admin_email:stritems_per_user:int=50settings=Settings()

Y luego usarlo en un archivomain.py:

fromfastapiimportFastAPIfrom.configimportsettingsapp=FastAPI()@app.get("/info")asyncdefinfo():return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}

Consejo

También necesitarías un archivo__init__.py como viste enAplicaciones Más Grandes - Múltiples Archivos.

Configuraciones en una dependencia

En algunas ocasiones podría ser útil proporcionar las configuraciones desde una dependencia, en lugar de tener un objeto global consettings que se use en todas partes.

Esto podría ser especialmente útil durante las pruebas, ya que es muy fácil sobrescribir una dependencia con tus propias configuraciones personalizadas.

El archivo de configuración

Proveniente del ejemplo anterior, tu archivoconfig.py podría verse como:

frompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):app_name:str="Awesome API"admin_email:stritems_per_user:int=50
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

frompydantic_settingsimportBaseSettingsclassSettings(BaseSettings):app_name:str="Awesome API"admin_email:stritems_per_user:int=50

Nota que ahora no creamos un instance por defectosettings = Settings().

El archivo principal de la app

Ahora creamos una dependencia que devuelve un nuevoconfig.Settings().

fromfunctoolsimportlru_cachefromtypingimportAnnotatedfromfastapiimportDepends,FastAPIfrom.configimportSettingsapp=FastAPI()@lru_cachedefget_settings():returnSettings()@app.get("/info")asyncdefinfo(settings:Annotated[Settings,Depends(get_settings)]):return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfunctoolsimportlru_cachefromfastapiimportDepends,FastAPIfrom.configimportSettingsapp=FastAPI()@lru_cachedefget_settings():returnSettings()@app.get("/info")asyncdefinfo(settings:Settings=Depends(get_settings)):return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}

Consejo

Hablaremos del@lru_cache en un momento.

Por ahora puedes asumir queget_settings() es una función normal.

Y luego podemos requerirlo desde lapath operation function como una dependencia y usarlo donde lo necesitemos.

fromfunctoolsimportlru_cachefromtypingimportAnnotatedfromfastapiimportDepends,FastAPIfrom.configimportSettingsapp=FastAPI()@lru_cachedefget_settings():returnSettings()@app.get("/info")asyncdefinfo(settings:Annotated[Settings,Depends(get_settings)]):return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfunctoolsimportlru_cachefromfastapiimportDepends,FastAPIfrom.configimportSettingsapp=FastAPI()@lru_cachedefget_settings():returnSettings()@app.get("/info")asyncdefinfo(settings:Settings=Depends(get_settings)):return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}

Configuraciones y pruebas

Luego sería muy fácil proporcionar un objeto de configuraciones diferente durante las pruebas al crear una sobrescritura de dependencia paraget_settings:

fromfastapi.testclientimportTestClientfrom.configimportSettingsfrom.mainimportapp,get_settingsclient=TestClient(app)defget_settings_override():returnSettings(admin_email="testing_admin@example.com")app.dependency_overrides[get_settings]=get_settings_overridedeftest_app():response=client.get("/info")data=response.json()assertdata=={"app_name":"Awesome API","admin_email":"testing_admin@example.com","items_per_user":50,}
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfastapi.testclientimportTestClientfrom.configimportSettingsfrom.mainimportapp,get_settingsclient=TestClient(app)defget_settings_override():returnSettings(admin_email="testing_admin@example.com")app.dependency_overrides[get_settings]=get_settings_overridedeftest_app():response=client.get("/info")data=response.json()assertdata=={"app_name":"Awesome API","admin_email":"testing_admin@example.com","items_per_user":50,}

En la sobrescritura de dependencia establecemos un nuevo valor para eladmin_email al crear el nuevo objetoSettings, y luego devolvemos ese nuevo objeto.

Luego podemos probar que se está usando.

Leer un archivo.env

Si tienes muchas configuraciones que posiblemente cambien mucho, tal vez en diferentes entornos, podría ser útil ponerlos en un archivo y luego leerlos desde allí como si fueran variables de entorno.

Esta práctica es lo suficientemente común que tiene un nombre, estas variables de entorno generalmente se colocan en un archivo.env, y el archivo se llama un "dotenv".

Consejo

Un archivo que comienza con un punto (.) es un archivo oculto en sistemas tipo Unix, como Linux y macOS.

Pero un archivo dotenv realmente no tiene que tener ese nombre exacto.

Pydantic tiene soporte para leer desde estos tipos de archivos usando un paquete externo. Puedes leer más enPydantic Settings: Dotenv (.env) support.

Consejo

Para que esto funcione, necesitaspip install python-dotenv.

El archivo.env

Podrías tener un archivo.env con:

ADMIN_EMAIL="deadpool@example.com"APP_NAME="ChimichangApp"

Leer configuraciones desde.env

Y luego actualizar tuconfig.py con:

frompydantic_settingsimportBaseSettings,SettingsConfigDictclassSettings(BaseSettings):app_name:str="Awesome API"admin_email:stritems_per_user:int=50model_config=SettingsConfigDict(env_file=".env")
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

frompydantic_settingsimportBaseSettings,SettingsConfigDictclassSettings(BaseSettings):app_name:str="Awesome API"admin_email:stritems_per_user:int=50model_config=SettingsConfigDict(env_file=".env")

Consejo

El atributomodel_config se usa solo para configuración de Pydantic. Puedes leer más enPydantic: Concepts: Configuration.

Aquí definimos la configuraciónenv_file dentro de tu clase PydanticSettings, y establecemos el valor en el nombre del archivo con el archivo dotenv que queremos usar.

Creando elSettings solo una vez conlru_cache

Leer un archivo desde el disco es normalmente una operación costosa (lenta), por lo que probablemente quieras hacerlo solo una vez y luego reutilizar el mismo objeto de configuraciones, en lugar de leerlo para cada request.

Pero cada vez que hacemos:

Settings()

se crearía un nuevo objetoSettings, y al crearse leería el archivo.env nuevamente.

Si la función de dependencia fuera simplemente así:

defget_settings():returnSettings()

crearíamos ese objeto para cada request, y estaríamos leyendo el archivo.env para cada request. ⚠️

Pero como estamos usando el decorador@lru_cache encima, el objetoSettings se creará solo una vez, la primera vez que se llame. ✔️

fromfunctoolsimportlru_cachefromtypingimportAnnotatedfromfastapiimportDepends,FastAPIfrom.importconfigapp=FastAPI()@lru_cachedefget_settings():returnconfig.Settings()@app.get("/info")asyncdefinfo(settings:Annotated[config.Settings,Depends(get_settings)]):return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}
🤓 Other versions and variants

Tip

Prefer to use theAnnotated version if possible.

fromfunctoolsimportlru_cachefromfastapiimportDepends,FastAPIfrom.importconfigapp=FastAPI()@lru_cachedefget_settings():returnconfig.Settings()@app.get("/info")asyncdefinfo(settings:config.Settings=Depends(get_settings)):return{"app_name":settings.app_name,"admin_email":settings.admin_email,"items_per_user":settings.items_per_user,}

Entonces, para cualquier llamada subsiguiente deget_settings() en las dependencias de los próximos requests, en lugar de ejecutar el código interno deget_settings() y crear un nuevo objetoSettings, devolverá el mismo objeto que fue devuelto en la primera llamada, una y otra vez.

Detalles Técnicos delru_cache

@lru_cache modifica la función que decora para devolver el mismo valor que se devolvió la primera vez, en lugar de calcularlo nuevamente, ejecutando el código de la función cada vez.

Así que la función debajo se ejecutará una vez por cada combinación de argumentos. Y luego, los valores devueltos por cada una de esas combinaciones de argumentos se utilizarán una y otra vez cada vez que la función sea llamada con exactamente la misma combinación de argumentos.

Por ejemplo, si tienes una función:

@lru_cachedefsay_hi(name:str,salutation:str="Ms."):returnf"Hello{salutation}{name}"

tu programa podría ejecutarse así:

sequenceDiagramparticipant code as Códigoparticipant function as say_hi()participant execute as Ejecutar función    rect rgba(0, 255, 0, .1)        code ->> function: say_hi(name="Camila")        function ->> execute: ejecutar código de la función        execute ->> code: devolver el resultado    end    rect rgba(0, 255, 255, .1)        code ->> function: say_hi(name="Camila")        function ->> code: devolver resultado almacenado    end    rect rgba(0, 255, 0, .1)        code ->> function: say_hi(name="Rick")        function ->> execute: ejecutar código de la función        execute ->> code: devolver el resultado    end    rect rgba(0, 255, 0, .1)        code ->> function: say_hi(name="Rick", salutation="Mr.")        function ->> execute: ejecutar código de la función        execute ->> code: devolver el resultado    end    rect rgba(0, 255, 255, .1)        code ->> function: say_hi(name="Rick")        function ->> code: devolver resultado almacenado    end    rect rgba(0, 255, 255, .1)        code ->> function: say_hi(name="Camila")        function ->> code: devolver resultado almacenado    end

En el caso de nuestra dependenciaget_settings(), la función ni siquiera toma argumentos, por lo que siempre devuelve el mismo valor.

De esa manera, se comporta casi como si fuera solo una variable global. Pero como usa una función de dependencia, entonces podemos sobrescribirla fácilmente para las pruebas.

@lru_cache es parte defunctools, que es parte del paquete estándar de Python, puedes leer más sobre él en lasdocs de Python para@lru_cache.

Resumen

Puedes usar Pydantic Settings para manejar las configuraciones o ajustes de tu aplicación, con todo el poder de los modelos de Pydantic.

  • Al usar una dependencia, puedes simplificar las pruebas.
  • Puedes usar archivos.env con él.
  • Usar@lru_cache te permite evitar leer el archivo dotenv una y otra vez para cada request, mientras te permite sobrescribirlo durante las pruebas.

[8]ページ先頭

©2009-2026 Movatter.jp