修复 FastAPI(Asyncpg + Docker)中的 “invalid literal for int() with base 10: 'None'” 错误

发布: (2026年3月18日 GMT+8 11:59)
4 分钟阅读
原文: Dev.to

看起来您只提供了来源链接,而没有贴出需要翻译的正文内容。请把您想要翻译的文本(包括标题、段落、代码块说明等)粘贴在这里,我会按照要求保留源链接并将内容翻译成简体中文。

Problem Overview

在使用 Docker 部署带有 Aiven PostgreSQL 的 FastAPI 应用时,可能会遇到以下回溯信息:

ValueError: invalid literal for int() with base 10: 'None'

SQLAlchemy 的 URL 解析器会把字符串 -None 解释为数据库 URL 中的端口部分,该 URL 看起来像:

postgresql+asyncpg://user:pass@host:None/dbname

原因

SQLAlchemy 的 make_url() 函数尝试将端口部分转换为整数。如果用于构建 URL 的变量的值为 None,f‑string 插值会把它变成字面字符串 "None",从而导致错误。

典型代码模式:

import os

DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_HOST = os.getenv("DB_HOST")
DB_PORT = os.getenv("DB_PORT")
DB_NAME = os.getenv("DB_NAME")

ASYNC_DB_URL = f"postgresql+asyncpg://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
engine = create_async_engine(ASYNC_DB_URL)

如果容器环境中缺少 DB_PORT(或其他任何组件),它会变为 None,从而生成带有 :None 的错误 URL。

将完整的 DATABASE_URL 与基于组件的构造混合使用的回退逻辑也可能触发此问题:

ASYNC_DB_URL = os.getenv("DATABASE_URL") or f"postgresql+asyncpg://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"

DATABASE_URL 不存在时,构造的 URL 会继承 None 端口。

解决方案

使用单一的 DATABASE_URL

建议使用包含完整连接字符串的单个环境变量。提前验证其是否存在,并避免从多个组件拼接 URL。

import os
from sqlalchemy.ext.asyncio import create_async_engine

DATABASE_URL = os.getenv("DATABASE_URL")
if not DATABASE_URL:
    raise ValueError("DATABASE_URL environment variable is not set")

engine = create_async_engine(DATABASE_URL)

为 asyncpg 调整 Scheme

Aiven(以及许多云服务提供商)会提供带有 postgres:// scheme 的 URL。为了兼容 SQLAlchemy 的异步支持,需要将其替换为 postgresql+asyncpg://

raw_url = os.getenv("DATABASE_URL")
if raw_url and raw_url.startswith("postgres://"):
    raw_url = raw_url.replace("postgres://", "postgresql+asyncpg://", 1)

engine = create_async_engine(raw_url)

完整示例(database.py

import os
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker, declarative_base

# 获取并验证完整的 URL
DATABASE_URL = os.getenv("DATABASE_URL")
if not DATABASE_URL:
    raise ValueError("DATABASE_URL environment variable is required")

# 确保使用 asyncpg 驱动的 scheme
if DATABASE_URL.startswith("postgres://"):
    DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql+asyncpg://", 1)

# 创建异步引擎
engine = create_async_engine(DATABASE_URL, echo=True)

# 会话工厂
AsyncSessionLocal = sessionmaker(
    bind=engine,
    class_=AsyncSession,
    expire_on_commit=False,
)

# 模型基类
Base = declarative_base()

Docker 配置

通过 .env 文件或直接在 docker‑compose.yml 中将 DATABASE_URL 传递给容器。

services:
  app:
    build: .
    env_file:
      - .env

.env 示例:

DATABASE_URL=postgresql+asyncpg://avnadmin:password@host:port/defaultdb?sslmode=require

最佳实践

  • 单一真实来源:将完整的连接字符串存放在一个变量中。
  • 提前验证:如果缺少必需的变量,抛出明确的错误。
  • 防御式编程:避免从碎片化的组件拼接 URL。
  • 一致的方案:在使用 SQLAlchemy 异步时使用 postgresql+asyncpg://
  • 最小化环境变量:降低在不同环境中出现不匹配或缺失值的风险。

通过将配置合并为单一、经过验证的 DATABASE_URL,可以消除 None 端口错误,并简化在 Docker、Kubernetes 或其他平台上的部署。

0 浏览
Back to Blog

相关文章

阅读更多 »

阻止多租户应用中的数据泄漏

为什么仅靠应用逻辑不足以满足需求:数据库级行级安全的案例 你已经构建了一个强大的多租户 SaaS。你已经实现了 tenant_id f…

下一个排列

问题描述:任务是计算给定数字数组的下一个排列。排列是相同元素的重新排列,而下一个…