一、Pydantic是什么?为什么这么好用?
Pydantic是一个基于Python类型提示的数据验证和设置管理工具库,它能自动检查数据类型、进行类型转换,还能从.env文件中读取环境变量,让你的配置管理变得简单又安全。
✨ Pydantic 2.x的优势:
- 基于标准Python类型注解
- 自动类型转换与错误提示
- 支持嵌套模型和复杂校验
- 通过
pydantic-settings支持环境变量 - 性能提升:2.x内核部分用Rust重写,比1.x快2倍
二、安装Pydantic和相关依赖
ini
Bash
编辑
1# 安装Pydantic 2.x和pydantic-settings
2pip install pydantic pydantic-settings==2.8.1
💡 提示:
pydantic-settings是Pydantic 2.x的环境管理专用包,会自动安装pydantic和python-dotenv。
三、创建.env文件
在项目根目录创建.env文件,添加你的环境变量:
ini
Ini
编辑
1# .env 文件示例
2DATABASE_URL=postgres://user:password@localhost:5432/mydb
3API_KEY=your_api_key_here
4DEBUG_MODE=True
⚠️ 重要:记得将
.env添加到.gitignore中,避免敏感信息泄露!
四、使用Pydantic加载.env配置
1. 创建配置文件
在项目中创建config.py:
ini
Python
编辑
1from pydantic_settings import BaseSettings, SettingsConfigDict
2
3class Settings(BaseSettings):
4 DATABASE_URL: str
5 API_KEY: str
6 DEBUG_MODE: bool = False # 提供默认值
7
8 model_config = SettingsConfigDict(
9 env_file=".env", # 指定.env文件位置
10 env_file_encoding='utf-8', # 编码
11 extra='ignore' # 忽略未在配置中定义的环境变量
12 )
13
14# 实例化配置
15settings = Settings()
2. 在项目中使用配置
python
Python
编辑
1# 使用示例
2def connect_db():
3 print(f"Connecting to {settings.DATABASE_URL} with debug mode: {settings.DEBUG_MODE}")
4
5# 调用
6connect_db()
五、在普通Python虚拟环境中使用
1. 创建虚拟环境(venv)
bash
Bash
编辑
1# 创建虚拟环境
2python -m venv venv
3
4# 激活虚拟环境
5# Windows
6venv\Scripts\activate
7# macOS/Linux
8source venv/bin/activate
9
10# 安装依赖
11pip install pydantic pydantic-settings
2. 验证配置
在虚拟环境中运行一个简单的测试脚本:
python
Python
编辑
1# test_config.py
2from config import settings
3
4print(f"Database URL: {settings.DATABASE_URL}")
5print(f"API Key: {settings.API_KEY}")
6print(f"Debug Mode: {settings.DEBUG_MODE}")
bash
Bash
编辑
1# 运行测试
2python test_config.py
如果一切正常,你会看到从.env中读取的配置信息。
六、在Docker中使用Pydantic和.env
Docker部署时,我们通常会将.env文件作为配置的一部分,但要注意不要将.env文件添加到Docker镜像中(避免泄露敏感信息)。
1. Docker部署方案
方案一:通过命令行参数-e传递环境变量
bash
Dockerfile
编辑
1# Dockerfile
2FROM python:3.10-slim
3
4WORKDIR /app
5
6# 复制依赖文件
7COPY requirements.txt .
8RUN pip install --no-cache-dir -r requirements.txt
9
10# 复制应用代码
11COPY . .
12
13# 设置环境变量(推荐方式)
14# 通过docker run -e传递,或使用.env文件
15# EXPOSE 5000
16CMD ["python", "app.py"]
ini
Bash
编辑
1# 运行容器(通过命令行传递环境变量)
2docker run -p 5000:5000 \
3 -e DATABASE_URL="postgres://user:password@db:5432/mydb" \
4 -e API_KEY="your_api_key" \
5 -e DEBUG_MODE="True" \
6 my-python-app
方案二:使用.env文件(Docker Compose推荐)
在Docker compose中使用(env_file)
yaml
Yaml
编辑
1# docker-compose.yml
2version: '3'
3services:
4 app:
5 build: .
6 ports:
7 - "5000:5000"
8 env_file:
9 - .env
💡 提示:在
docker-compose.yml中指定env_file,Docker会自动读取该文件中的环境变量。
在docker中使用(--env_file)
ini
1# 运行容器(通过命令行传递环境变量)
2docker run -p 5000:5000 \
3 --env-file $(pwd)/.env.prod \
4 -e API_KEY="your_api_key" \
5 -e DEBUG_MODE="True" \
6 my-python-app
2. Docker部署完整示例
- 创建项目结构:
Text
编辑
1project/
2├── app.py
3├── config.py
4├── .env
5├── requirements.txt
6└── Dockerfile
config.py(已包含在前面部分)app.py:
python
Python
编辑
1from config import settings
2
3def main():
4 print(f"Application starting with DB: {settings.DATABASE_URL}")
5 # 你的应用逻辑
6
7if __name__ == "__main__":
8 main()
Dockerfile:
sql
Dockerfile
编辑
1FROM python:3.10-slim
2
3WORKDIR /app
4
5COPY requirements.txt .
6RUN pip install --no-cache-dir -r requirements.txt
7
8COPY . .
9
10EXPOSE 5000
11CMD ["python", "app.py"]
requirements.txt:
ini
Text
编辑
1pydantic
2pydantic-settings==2.8.1
- 构建并运行:
bash
Bash
编辑
1# 构建镜像
2docker build -t my-app .
3
4# 运行容器(使用.env文件)
5docker run -p 5000:5000 -v $(pwd)/.env:/app/.env my-app # 直接将环境变量映射到容器中,不可取
💡 重要:
-v $(pwd)/.env:/app/.env将本地的.env文件挂载到容器中,确保配置正确读取。
七、常见问题解决
1. 无法读取.env文件
- 确认文件名是
.env(注意开头的点) - 确认文件路径正确(在Docker中,确保.env在镜像构建上下文中)
- 检查
model_config中env_file的路径
2. 环境变量类型转换问题
Pydantic会自动将环境变量转换为指定类型,但要注意:
DEBUG_MODE在.env中是True,在Python中会是字符串,需要在配置中指定为bool- 解决方法:在
Settings类中明确指定类型,如DEBUG_MODE: bool = False
3. 敏感信息泄露
- 永远不要将.env文件提交到Git
- 在Docker中,使用
docker secret或云服务的密钥管理 - 使用
env_file时,确保.env文件不在Git中
八、高级技巧
1. 多环境配置
ini
Python
编辑
1# config.py
2class Settings(BaseSettings):
3 ENVIRONMENT: str = "dev"
4
5 class Config:
6 env_file = f".env.{ENVIRONMENT}"
7 env_file_encoding = 'utf-8'
然后创建.env.dev、.env.prod等文件,通过设置ENVIRONMENT环境变量切换。
2. 使用@env()函数(Data API Builder)
如果你在使用Data API Builder,可以这样使用:
perl
Json
编辑
1{
2 "data-source": {
3 "connection-string": "@env('DATABASE_URL')"
4 }
5}
3. 与FastAPI集成
kotlin
Python
编辑
1from fastapi import FastAPI
2from config import settings
3
4app = FastAPI()
5
6@app.get("/")
7def read_root():
8 return {"database": settings.DATABASE_URL}
总结
Pydantic + .env的组合是Python配置管理的黄金搭档!它让你的项目配置变得清晰、安全、可维护。
- 在普通Python环境中,用venv隔离环境,用Pydantic读取.env
- 在Docker部署 中,通过
env_file或命令行传递环境变量 - 保持
.env文件在.gitignore中,保护敏感信息
九、实际使用遇到的问题汇总
1. 带空格的字符串
原本以为,带空格的值,可能需要加单引号或者双引号,以避免解析不全的问题。然而这样实际反而会出问题。 带空格的字符串不需要加单引号或者双引号,否则引号会被解析为值的一部分,且pydantic的值为=右侧的值,故不会受值中间的空格影响
.env
a=a b //解析为a="a b"
a="a b" //解析为a='"a b"'
2. 列表元素
我的使用场景是需要传入两个字符串,且字符串的取值是固定的。 例如
python
# config.py
from pydantic-settings import BaseSettings
from typing import List, Literal
class Settings(BaseSettings):
lang:List[[Literal["python","java","c","go"]]
text
# .env
LANG=python,java # 解析失败,未解析为列表
LANG="python","java" # 也解析失败
LANG=["python","java"] # 可行
3. .env文件命名
实际上,并非只可使用.env命名,加其他后缀也可以,比如.env.test,.env.prod等 但是必须显式声明
python
# config.py
from pydantic-settings import BaseSettings
from typing import List, Literal
class Settings(BaseSettings):
lang:List[[Literal["python","java","c","go"]]
class Config:
env_file = ".env.prod" # 声明env文件名称
docker
docker run -p 5000:5000 \
--env-file $(pwd)/.env.prod \
-e API_KEY="your_api_key" \
-e DEBUG_MODE="True" \
my-python-app
4. 环境变量前缀env_prefix
env_prefix非必选项,可用不做设置,但是如果有有个环境,或者服务需要做区分时,可以设置用作区分。 .env中的环境变量去掉env_prefix后,即为配置文件中的环境变量 例如
python
# config.py
from pydantic-settings import BaseSettings
from typing import List, Literal
class Settings(BaseSettings):
lang:List[[Literal["python","java","c","go"]]
class Config:
env_file = ".env.prod" # 声明env文件名称
env_prefix=test
text
# .env
TEST_LANG=["python","java"] # 可行
5. .env文件中变量名为对应的python配置类中的环境变量全部字母大写
6. .env文件中只存放不敏感的环境变量,敏感环境变量可以使用-e参数在docker运行时设置
7. pydantic-settings接受默认值,但是如果是必填项,则不设默认值
8. pydantic支持参数类型校验,与python的类型声明用法完全一致
9. 同一个环境变量,不同设置方式的优先顺序
pydantic-settings 完全支持为从 .env 文件读取的环境变量设置默认值 ,但仅在未找到环境变量时才会使用这些默认值 -1-4-10。
理解其工作原理和最佳实践至关重要,这能帮你构建健壮的配置系统。
⚙️ 默认值的工作原理与优先级
pydantic-settings 的配置加载遵循一个固定的优先级顺序。核心原则是:优先级高的来源会覆盖优先级低的来源。
其四层加载优先级如下(从高到低):
| 优先级 | 配置来源 | 说明 | 示例 |
|---|---|---|---|
| 1. 最高 | 初始化参数 | 实例化模型时直接传入的值。 | Settings(api_key="直接传入的值") |
| 2. 次高 | 系统环境变量 | 操作系统中的环境变量。 | 在终端设置 export APP_API_KEY=env_value |
| 3. 中 | .env 文件变量 |
项目目录下的 .env 文件中定义的值-1-4。 |
在 .env 中写 APP_API_KEY=dotenv_value |
| 4. 最低 | 模型字段默认值 | 在 Settings 类中为字段定义的默认值。 |
api_key: str = "default_value" |
📝 如何设置默认值
设置默认值非常简单,主要有以下两种方式:
-
直接赋值:这是最直接的方法,在字段类型注解后直接赋值。
pythonfrom pydantic_settings import BaseSettings class Settings(BaseSettings): database_host: str = "localhost" # 默认值 api_key: str # 没有默认值,必须从环境变量或.env文件提供 port: int = 8000 # 默认值,并自动完成类型转换 -
使用
Field函数 :当需要更复杂的配置(如设置别名、添加描述)时,可以使用Field。pythonfrom pydantic_settings import BaseSettings from pydantic import Field class Settings(BaseSettings): db_host: str = Field( default="127.0.0.1", # 默认值 validation_alias="DB_HOST" # 指定从 DB_HOST 环境变量读取 )
✅ 是否建议设置默认值?分情况讨论
这取决于配置项的性质和项目的运行环境。
建议设置默认值的情况
- 本地开发/测试环境:为非敏感配置(如数据库端口、日志级别)设置本地默认值,可以简化开发流程。
- 非关键且有合理后备值的配置:例如,应用名称、超时时间、可选功能的开关。
- 提供清晰的配置示例:默认值可以作为一种配置格式的文档,让其他开发者快速理解。
不建议设置默认值(或应设置为空值)的情况
- 敏感信息 :绝对不要 为
API密钥、数据库密码、加密盐等敏感信息设置硬编码的默认值,尤其是生产环境的。应强制从外部环境变量或保密管理服务加载-4。 - 环境差异性大的配置 :如数据库连接字符串,在不同环境(开发、测试、生产)中必然不同,应由环境变量或
.env文件明确指定。 - 防止本地配置泄漏到生产环境:如果本地开发使用了带默认值的配置,可能会无意中让生产环境应用运行在不正确的配置下。