Flask アプリを Render にデプロイし、PostgreSQL と接続するだけのはずが、
実際には Python バージョンの不一致、psycopg2 の非対応、SQLAlchemy の仕様変更、アプリ構造の問題など、複数の技術的課題が重なった。
この記事では、実際に遭遇したエラーと、それぞれの技術的な原因・解決策をまとめる。
## 1. Render が Python 3.13 を強制してくる問題
現象
runtime.txt に python-3.12.10 を書いても Render が無視し、
ビルドログに以下のように出る:
Using Python version 3.13.x
影響
psycopg2 が Python 3.13 に非対応のため、ImportError が発生。
ImportError: undefined symbol: _PyInterpreterState_Get
原因
Render の Python 自動判定が壊れており、runtime.txt が反映されない。
解決策
psycopg2 を捨てて psycopg3(psycopg[binary])に移行する。
requirements.txt:
psycopg[binary]
psycopg3 は Python 3.13 に対応しているため、
Render のバージョン問題を完全に回避できる。
## 2. SQLAlchemy が psycopg2 を探し続ける問題
現象
psycopg3 を入れても、SQLAlchemy が内部で psycopg2 を探して落ちる。
ModuleNotFoundError: No module named 'psycopg2'
原因
DATABASE_URL が psycopg2 用の形式になっている。
解決策
接続 URL を psycopg3 用に変更する。
Before(psycopg2)
postgresql://user:pass@host:5432/dbname
After(psycopg3)
postgresql+psycopg://user:pass@host:5432/dbname
SQLAlchemy のドライバ選択は URL で決まるため、+psycopg を付けることで psycopg3 が使われる。
## 3. SQLAlchemy のインスタンスが二重生成されていた問題
現象
RuntimeError: The current Flask app is not registered with this 'SQLAlchemy' instance.
原因
app.py と models.py の両方で SQLAlchemy() を生成していた。
# app.py
db = SQLAlchemy(app)
# models.py
db = SQLAlchemy() # ← これが別インスタンス
解決策
db は app.py で1つだけ作り、models.py ではそれを import する。
app.py
db = SQLAlchemy(app)
from models import Todo
models.py
from app import db
class Todo(db.Model):
...
これで Flask アプリとモデルが同じ db インスタンスを共有できる。
## 4. SQLAlchemy 2.x の仕様変更による text() 必須化
現象
Textual SQL expression 'SELECT 1' should be explicitly declared as text('SELECT 1')
原因
SQLAlchemy 2.0 以降、
生 SQL を実行する場合は text() で包む必要がある。
解決策
from sqlalchemy import text
db.session.execute(text('SELECT 1'))
## 5. 最終確認:PostgreSQL への接続成功
すべての修正後 /dbtest を叩いた結果:
PostgreSQL OK
これで Flask アプリが Render 上で PostgreSQL と正常に通信できることが確認できた。
## まとめ:今回の技術的ポイント
| 問題 | 原因 | 解決策 |
|---|---|---|
| psycopg2 ImportError | Python 3.13 非対応 | psycopg[binary] に移行 |
| SQLAlchemy が psycopg2 を探す | DATABASE_URL の形式 | postgresql+psycopg:// に変更 |
| SQLAlchemy RuntimeError | db インスタンスの二重生成 | models.py の db を app.py のものに統一 |
| SELECT 1 エラー | SQLAlchemy 2.x の仕様変更 | text() を使用 |
## 再発防止のためのベストプラクティス
- Render は Python バージョンを強制することがある
→ psycopg3 を使うと安定する - SQLAlchemy の db はアプリ全体で1つだけ
- DATABASE_URL のドライバ指定は必ず確認
- SQLAlchemy 2.x では text() を使う
- デプロイログは必ず最初から読む(Python バージョンが重要)
