django-cloud-sql-postgres

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Django on Google Cloud SQL PostgreSQL

Django 搭配 Google Cloud SQL PostgreSQL 部署指南

Status: Production Ready Last Updated: 2026-01-24 Dependencies: None Latest Versions:
Django@5.1
,
psycopg2-binary@2.9.9
,
gunicorn@23.0.0
,
google-cloud-sql-connector@1.12.0

状态:生产就绪 最后更新:2026-01-24 依赖项:无 最新版本:
Django@5.1
,
psycopg2-binary@2.9.9
,
gunicorn@23.0.0
,
google-cloud-sql-connector@1.12.0

Quick Start (10 Minutes)

快速开始(10分钟)

1. Install Dependencies

1. 安装依赖项

bash
pip install Django psycopg2-binary gunicorn
For Cloud SQL Python Connector (recommended for local dev):
bash
pip install "cloud-sql-python-connector[pg8000]"
Why this matters:
  • psycopg2-binary
    is the PostgreSQL adapter for Django
  • gunicorn
    is required for App Engine Standard (Python 3.10+)
  • Cloud SQL Python Connector provides secure connections without SSH tunneling
bash
pip install Django psycopg2-binary gunicorn
对于Cloud SQL Python Connector(推荐用于本地开发):
bash
pip install "cloud-sql-python-connector[pg8000]"
重要性说明:
  • psycopg2-binary
    是Django的PostgreSQL适配库
  • gunicorn
    是App Engine标准环境(Python 3.10+)的必需组件
  • Cloud SQL Python Connector 无需SSH隧道即可建立安全连接

2. Configure Django Settings

2. 配置Django设置

settings.py (production with Unix socket):
python
import os
settings.py(生产环境使用Unix套接字):
python
import os

Detect App Engine environment

Detect App Engine environment

IS_APP_ENGINE = os.getenv('GAE_APPLICATION', None)
if IS_APP_ENGINE: # Production: Connect via Unix socket DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ['DB_NAME'], 'USER': os.environ['DB_USER'], 'PASSWORD': os.environ['DB_PASSWORD'], 'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}", 'PORT': '', # Empty for Unix socket } } else: # Local development: Connect via Cloud SQL Proxy DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DB_NAME', 'mydb'), 'USER': os.environ.get('DB_USER', 'postgres'), 'PASSWORD': os.environ.get('DB_PASSWORD', ''), 'HOST': '127.0.0.1', 'PORT': '5432', } }

**CRITICAL:**
- App Engine connects via **Unix socket** at `/cloudsql/PROJECT:REGION:INSTANCE`
- Local development requires **Cloud SQL Auth Proxy** on `127.0.0.1:5432`
- Never hardcode connection strings - use environment variables
IS_APP_ENGINE = os.getenv('GAE_APPLICATION', None)
if IS_APP_ENGINE: # Production: Connect via Unix socket DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ['DB_NAME'], 'USER': os.environ['DB_USER'], 'PASSWORD': os.environ['DB_PASSWORD'], 'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}", 'PORT': '', # Empty for Unix socket } } else: # Local development: Connect via Cloud SQL Proxy DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DB_NAME', 'mydb'), 'USER': os.environ.get('DB_USER', 'postgres'), 'PASSWORD': os.environ.get('DB_PASSWORD', ''), 'HOST': '127.0.0.1', 'PORT': '5432', } }

**关键注意事项**:
- App Engine 通过 **Unix套接字** 连接,路径为 `/cloudsql/PROJECT:REGION:INSTANCE`
- 本地开发需要在 `127.0.0.1:5432` 运行 **Cloud SQL Auth Proxy**
- 切勿硬编码连接字符串 - 使用环境变量

3. Create app.yaml

3. 创建app.yaml

yaml
runtime: python310
entrypoint: gunicorn -b :$PORT myproject.wsgi:application

env_variables:
  DB_NAME: "mydb"
  DB_USER: "postgres"
  CLOUD_SQL_CONNECTION_NAME: "project-id:region:instance-name"
yaml
runtime: python310
entrypoint: gunicorn -b :$PORT myproject.wsgi:application

env_variables:
  DB_NAME: "mydb"
  DB_USER: "postgres"
  CLOUD_SQL_CONNECTION_NAME: "project-id:region:instance-name"

Cloud SQL connection

Cloud SQL connection

beta_settings: cloud_sql_instances: "project-id:region:instance-name"
handlers:
  • url: /static static_dir: static/
  • url: /.* script: auto secure: always

**CRITICAL:**
- `beta_settings.cloud_sql_instances` enables the Unix socket at `/cloudsql/...`
- DB_PASSWORD should be set via `gcloud app deploy` or Secret Manager, not in app.yaml

---
beta_settings: cloud_sql_instances: "project-id:region:instance-name"
handlers:
  • url: /static static_dir: static/
  • url: /.* script: auto secure: always

**关键注意事项**:
- `beta_settings.cloud_sql_instances` 用于启用 `/cloudsql/...` 路径的Unix套接字
- DB_PASSWORD 应通过 `gcloud app deploy` 或Secret Manager设置,不要写入app.yaml

---

The 6-Step Setup Process

六步完整部署流程

Step 1: Create Cloud SQL Instance

步骤1:创建Cloud SQL实例

bash
undefined
bash
undefined

Create PostgreSQL instance

Create PostgreSQL instance

gcloud sql instances create myinstance
--database-version=POSTGRES_15
--tier=db-f1-micro
--region=us-central1
gcloud sql instances create myinstance
--database-version=POSTGRES_15
--tier=db-f1-micro
--region=us-central1

Create database

Create database

gcloud sql databases create mydb --instance=myinstance
gcloud sql databases create mydb --instance=myinstance

Create user

Create user

gcloud sql users create postgres
--instance=myinstance
--password=YOUR_SECURE_PASSWORD

**Key Points:**
- Use `POSTGRES_15` or later for best compatibility
- `db-f1-micro` is cheapest for dev ($7-10/month), use `db-g1-small` or higher for production
- Note the **connection name**: `PROJECT_ID:REGION:INSTANCE_NAME`

---
gcloud sql users create postgres
--instance=myinstance
--password=YOUR_SECURE_PASSWORD

**核心要点**:
- 使用 `POSTGRES_15` 或更高版本以获得最佳兼容性
- `db-f1-micro` 是开发环境最经济的选项(每月7-10美元),生产环境建议使用 `db-g1-small` 或更高配置
- 记录 **连接名称**:`PROJECT_ID:REGION:INSTANCE_NAME`

---

Step 2: Configure Django Project

步骤2:配置Django项目

requirements.txt:
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0
settings.py additions:
python
import os
requirements.txt:
Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0
settings.py 新增配置:
python
import os

Security settings for production

Security settings for production

DEBUG = os.environ.get('DEBUG', 'False') == 'True' ALLOWED_HOSTS = [ '.appspot.com', '.run.app', 'localhost', '127.0.0.1', ]
DEBUG = os.environ.get('DEBUG', 'False') == 'True' ALLOWED_HOSTS = [ '.appspot.com', '.run.app', 'localhost', '127.0.0.1', ]

Static files with WhiteNoise

Static files with WhiteNoise

STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static') MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static') MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Database connection pooling

Database connection pooling

DATABASES['default']['CONN_MAX_AGE'] = 60 # Keep connections open for 60 seconds

**Why these settings:**
- `CONN_MAX_AGE=60` reduces connection overhead (Cloud SQL has connection limits)
- WhiteNoise serves static files without Cloud Storage
- `ALLOWED_HOSTS` must include `.appspot.com` for App Engine

---
DATABASES['default']['CONN_MAX_AGE'] = 60 # Keep connections open for 60 seconds

**配置原因**:
- `CONN_MAX_AGE=60` 减少连接开销(Cloud SQL有连接数限制)
- WhiteNoise 无需Cloud Storage即可托管静态文件
- `ALLOWED_HOSTS` 必须包含 `.appspot.com` 以适配App Engine

---

Step 3: Set Up Local Development with Cloud SQL Proxy

步骤3:配置本地开发环境与Cloud SQL Proxy

Install Cloud SQL Auth Proxy:
bash
undefined
安装Cloud SQL Auth Proxy:
bash
undefined

macOS

macOS

brew install cloud-sql-proxy
brew install cloud-sql-proxy

Linux

Linux


**Run the proxy:**
```bash

**运行代理:**
```bash

Authenticate first

Authenticate first

gcloud auth application-default login
gcloud auth application-default login

Start proxy (runs on 127.0.0.1:5432)

Start proxy (runs on 127.0.0.1:5432)

./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME
./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME

Or with specific port

Or with specific port

./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME --port=5432

**Set environment variables for local dev:**
```bash
export DB_NAME=mydb
export DB_USER=postgres
export DB_PASSWORD=your_password
export DEBUG=True
Key Points:
  • Proxy creates a secure tunnel to Cloud SQL
  • No need to whitelist your IP address
  • Works with both password and IAM authentication

./cloud-sql-proxy PROJECT_ID:REGION:INSTANCE_NAME --port=5432

**设置本地开发环境变量:**
```bash
export DB_NAME=mydb
export DB_USER=postgres
export DB_PASSWORD=your_password
export DEBUG=True
核心要点:
  • 代理会创建到Cloud SQL的安全隧道
  • 无需将IP地址加入白名单
  • 支持密码认证与IAM认证两种方式

Step 4: Run Migrations

步骤4:执行数据库迁移

bash
undefined
bash
undefined

Local (with proxy running)

Local (with proxy running)

python manage.py migrate
python manage.py migrate

Verify connection

Verify connection

python manage.py dbshell

**For production migrations (via Cloud Build or local with proxy):**
```bash
python manage.py dbshell

**生产环境迁移方式(通过Cloud Build或本地代理):**
```bash

Option 1: Run locally with proxy

Option 1: Run locally with proxy

./cloud-sql-proxy PROJECT:REGION:INSTANCE & python manage.py migrate
./cloud-sql-proxy PROJECT:REGION:INSTANCE & python manage.py migrate

Option 2: Use Cloud Build (recommended)

Option 2: Use Cloud Build (recommended)

See references/cloud-build-migrations.md

See references/cloud-build-migrations.md


---

---

Step 5: Configure Gunicorn

步骤5:配置Gunicorn

gunicorn.conf.py (optional, for fine-tuning):
python
import multiprocessing
gunicorn.conf.py(可选,用于精细调优):
python
import multiprocessing

Workers

Workers

workers = 2 # App Engine Standard limits this threads = 4 worker_class = 'gthread'
workers = 2 # App Engine Standard limits this threads = 4 worker_class = 'gthread'

Timeout (App Engine has 60s limit for standard, 3600s for flexible)

Timeout (App Engine has 60s limit for standard, 3600s for flexible)

timeout = 55
timeout = 55

Logging

Logging

accesslog = '-' errorlog = '-' loglevel = 'info'
accesslog = '-' errorlog = '-' loglevel = 'info'

Bind (App Engine sets $PORT)

Bind (App Engine sets $PORT)

bind = f"0.0.0.0:{os.environ.get('PORT', '8080')}"

**app.yaml entrypoint options:**
```yaml
bind = f"0.0.0.0:{os.environ.get('PORT', '8080')}"

**app.yaml 启动命令选项:**
```yaml

Simple (recommended for most cases)

Simple (recommended for most cases)

entrypoint: gunicorn -b :$PORT myproject.wsgi:application
entrypoint: gunicorn -b :$PORT myproject.wsgi:application

With config file

With config file

entrypoint: gunicorn -c gunicorn.conf.py myproject.wsgi:application
entrypoint: gunicorn -c gunicorn.conf.py myproject.wsgi:application

With workers and timeout

With workers and timeout

entrypoint: gunicorn -b :$PORT -w 2 -t 55 myproject.wsgi:application

**Key Points:**
- App Engine Standard limits workers (F1: 1 worker, F2: 2 workers)
- Use `gthread` worker class for I/O-bound Django apps
- Set timeout < 60s to avoid App Engine killing requests

---
entrypoint: gunicorn -b :$PORT -w 2 -t 55 myproject.wsgi:application

**核心要点**:
- App Engine标准环境对worker数量有限制(F1:1个worker,F2:2个worker)
- 对于I/O密集型Django应用,使用`gthread` worker类型
- 超时设置需小于60秒,避免App Engine终止请求

---

Step 6: Deploy to App Engine

步骤6:部署到App Engine

bash
undefined
bash
undefined

Collect static files

Collect static files

python manage.py collectstatic --noinput
python manage.py collectstatic --noinput

Deploy

Deploy

gcloud app deploy app.yaml
gcloud app deploy app.yaml

Set DB password via environment

Set DB password via environment

gcloud app deploy --set-env-vars="DB_PASSWORD=your_secure_password"
gcloud app deploy --set-env-vars="DB_PASSWORD=your_secure_password"

View logs

View logs

gcloud app logs tail -s default

**Verify deployment:**
```bash
gcloud app logs tail -s default

**验证部署结果:**
```bash

Open in browser

Open in browser

gcloud app browse
gcloud app browse

Check database connection

Check database connection

gcloud app logs read --service=default | grep -i database

---
gcloud app logs read --service=default | grep -i database

---

Critical Rules (Django + Cloud SQL)

Django + Cloud SQL 关键规则

ALWAYS DO:
  • Use Unix socket path
    /cloudsql/PROJECT:REGION:INSTANCE
    on App Engine
  • Set
    PORT=''
    (empty string) for Unix socket connections
  • Use Cloud SQL Auth Proxy for local development
  • Set
    CONN_MAX_AGE
    for connection pooling (30-60 seconds)
  • Use environment variables for database credentials
  • Use Secret Manager for production passwords
NEVER DO:
  • Put database password in
    app.yaml
    (use Secret Manager or env vars at deploy time)
  • Use
    HOST='localhost'
    on App Engine (must use Unix socket path)
  • Forget
    beta_settings.cloud_sql_instances
    in app.yaml
  • Set
    CONN_MAX_AGE=None
    (unlimited) - can exhaust connection pool
  • Skip SSL on Cloud SQL (it's enforced by default)

必须遵守:
  • 在App Engine上使用 Unix套接字 路径
    /cloudsql/PROJECT:REGION:INSTANCE
  • Unix套接字连接时设置
    PORT=''
    (空字符串)
  • 本地开发使用 Cloud SQL Auth Proxy
  • 设置
    CONN_MAX_AGE
    实现连接池(30-60秒)
  • 使用 环境变量 存储数据库凭证
  • 生产环境使用 Secret Manager 存储密码
严禁操作:
  • 不要将数据库密码写入
    app.yaml
    (使用Secret Manager或部署时设置环境变量)
  • 在App Engine上不要使用
    HOST='localhost'
    (必须使用Unix套接字路径)
  • 不要忘记在app.yaml中添加
    beta_settings.cloud_sql_instances
  • 不要设置
    CONN_MAX_AGE=None
    (无限制)- 会耗尽连接池
  • 不要跳过Cloud SQL的SSL配置(默认强制启用)

Known Issues Prevention

已知问题预防

This skill prevents 12 documented issues:
本指南可预防 12个已记录的常见问题:

Issue #1: OperationalError - No such file or directory

问题1:OperationalError - 找不到文件或目录

Error:
django.db.utils.OperationalError: could not connect to server: No such file or directory
Source: https://cloud.google.com/sql/docs/postgres/connect-app-engine-standard Why It Happens: App Engine can't find the Unix socket because
beta_settings.cloud_sql_instances
is missing in app.yaml Prevention: Always include
beta_settings.cloud_sql_instances: "PROJECT:REGION:INSTANCE"
in app.yaml
错误信息:
django.db.utils.OperationalError: could not connect to server: No such file or directory
来源:https://cloud.google.com/sql/docs/postgres/connect-app-engine-standard 问题原因:app.yaml中缺少
beta_settings.cloud_sql_instances
,导致App Engine无法找到Unix套接字 解决方法:确保app.yaml中包含
beta_settings.cloud_sql_instances: "PROJECT:REGION:INSTANCE"

Issue #2: Connection Refused on Local Development

问题2:本地开发时连接被拒绝

Error:
django.db.utils.OperationalError: connection refused
or
could not connect to server: Connection refused
Source: https://cloud.google.com/sql/docs/postgres/connect-auth-proxy Why It Happens: Cloud SQL Auth Proxy is not running or bound to wrong port Prevention: Start
cloud-sql-proxy PROJECT:REGION:INSTANCE
before running Django locally. Verify it's running on port 5432.
错误信息:
django.db.utils.OperationalError: connection refused
或
could not connect to server: Connection refused
来源:https://cloud.google.com/sql/docs/postgres/connect-auth-proxy 问题原因:Cloud SQL Auth Proxy未运行或绑定到错误端口 解决方法:在运行Django前启动
cloud-sql-proxy PROJECT:REGION:INSTANCE
,并确认其运行在5432端口

Issue #3: FATAL: password authentication failed

问题3:FATAL: password authentication failed

Error:
FATAL: password authentication failed for user "postgres"
Source: https://cloud.google.com/sql/docs/postgres/create-manage-users Why It Happens: Wrong password in environment variable, or user doesn't exist in Cloud SQL instance Prevention: Verify password with
gcloud sql users list --instance=INSTANCE
. Reset if needed:
gcloud sql users set-password postgres --instance=INSTANCE --password=NEW_PASSWORD
错误信息:
FATAL: password authentication failed for user "postgres"
来源:https://cloud.google.com/sql/docs/postgres/create-manage-users 问题原因:环境变量中的密码错误,或Cloud SQL实例中不存在该用户 解决方法:使用
gcloud sql users list --instance=INSTANCE
验证用户信息,必要时重置密码:
gcloud sql users set-password postgres --instance=INSTANCE --password=NEW_PASSWORD

Issue #4: Too Many Connections

问题4:连接数过多

Error:
FATAL: too many connections for role "postgres"
or
remaining connection slots are reserved
Source: https://cloud.google.com/sql/docs/postgres/quotas#connection_limits Why It Happens: Each request opens a new connection without pooling, exhausting the 25-100 connection limit Prevention: Set
CONN_MAX_AGE = 60
in Django settings. For high traffic, use PgBouncer or
django-db-connection-pool
.
错误信息:
FATAL: too many connections for role "postgres"
或
remaining connection slots are reserved
来源:https://cloud.google.com/sql/docs/postgres/quotas#connection_limits 问题原因:每个请求都新建连接且未使用连接池,耗尽了25-100的连接数限制 解决方法:在Django设置中设置
CONN_MAX_AGE = 60
。高流量场景下,使用PgBouncer或
django-db-connection-pool

Issue #5: App Engine Request Timeout

问题5:App Engine请求超时

Error:
DeadlineExceededError
or request terminated after 60 seconds Source: https://cloud.google.com/appengine/docs/standard/python3/how-requests-are-handled Why It Happens: Database query or migration takes longer than App Engine's 60-second limit Prevention: Set Gunicorn timeout to 55 seconds. For long-running tasks, use Cloud Tasks or Cloud Run Jobs.
错误信息:
DeadlineExceededError
或请求在60秒后被终止 来源:https://cloud.google.com/appengine/docs/standard/python3/how-requests-are-handled 问题原因:数据库查询或迁移耗时超过App Engine的60秒限制 解决方法:将Gunicorn超时设置为55秒。对于长时间运行的任务,使用Cloud Tasks或Cloud Run Jobs

Issue #6: Static Files 404 in Production

问题6:生产环境静态文件404

Error: Static files return 404, CSS/JS not loading Source: https://cloud.google.com/appengine/docs/standard/serving-static-files Why It Happens: Missing
static/
handler in app.yaml or
collectstatic
not run before deploy Prevention: Run
python manage.py collectstatic --noinput
before deploy. Include static handler in app.yaml.
错误信息:静态文件返回404,CSS/JS无法加载 来源:https://cloud.google.com/appengine/docs/standard/serving-static-files 问题原因:app.yaml中缺少
static/
处理器,或部署前未运行
collectstatic
解决方法:部署前运行
python manage.py collectstatic --noinput
,并在app.yaml中添加静态文件处理器

Issue #7: CSRF Verification Failed

问题7:CSRF验证失败

Error:
Forbidden (403) CSRF verification failed
Source: Django documentation on CSRF Why It Happens:
CSRF_TRUSTED_ORIGINS
not set for appspot.com domain Prevention: Add
CSRF_TRUSTED_ORIGINS = ['https://*.appspot.com']
to settings.py
错误信息:
Forbidden (403) CSRF verification failed
来源:Django官方CSRF文档 问题原因:未为appspot.com域名设置
CSRF_TRUSTED_ORIGINS
解决方法:在settings.py中添加
CSRF_TRUSTED_ORIGINS = ['https://*.appspot.com']

Issue #8: Database Not Found After Deployment

问题8:部署后数据库不存在

Error:
django.db.utils.OperationalError: FATAL: database "mydb" does not exist
Source: https://cloud.google.com/sql/docs/postgres/create-manage-databases Why It Happens: Database exists in Cloud SQL but
DB_NAME
environment variable is wrong Prevention: Verify database name:
gcloud sql databases list --instance=INSTANCE
. Ensure
DB_NAME
matches exactly.
错误信息:
django.db.utils.OperationalError: FATAL: database "mydb" does not exist
来源:https://cloud.google.com/sql/docs/postgres/create-manage-databases 问题原因:Cloud SQL中存在数据库,但
DB_NAME
环境变量配置错误 解决方法:使用
gcloud sql databases list --instance=INSTANCE
验证数据库名称,确保
DB_NAME
完全匹配

Issue #9: IAM Authentication Failure

问题9:IAM认证失败

Error:
FATAL: Cloud SQL IAM user authentication failed
Source: https://cloud.google.com/sql/docs/postgres/iam-logins Why It Happens: App Engine service account doesn't have
roles/cloudsql.instanceUser
role Prevention: Grant role:
gcloud projects add-iam-policy-binding PROJECT --member="serviceAccount:PROJECT@appspot.gserviceaccount.com" --role="roles/cloudsql.instanceUser"
错误信息:
FATAL: Cloud SQL IAM user authentication failed
来源:https://cloud.google.com/sql/docs/postgres/iam-logins 问题原因:App Engine服务账号没有
roles/cloudsql.instanceUser
角色 解决方法:授予角色:
gcloud projects add-iam-policy-binding PROJECT --member="serviceAccount:PROJECT@appspot.gserviceaccount.com" --role="roles/cloudsql.instanceUser"

Issue #10: Migrations Fail in Production

问题10:生产环境迁移失败

Error: Migrations timeout or can't run during deployment Source: https://cloud.google.com/sql/docs/postgres/connect-build Why It Happens: App Engine deploy doesn't provide a migration step; running in entrypoint times out Prevention: Run migrations separately via Cloud Build, or locally with Cloud SQL Proxy before deploying.
错误信息:迁移超时或部署期间无法执行 来源:https://cloud.google.com/sql/docs/postgres/connect-build 问题原因:App Engine部署过程中没有迁移步骤,在启动命令中运行迁移会超时 解决方法:通过Cloud Build执行迁移,或在部署前使用本地代理运行迁移

Issue #11: SECRET_KEY Exposed

问题11:SECRET_KEY泄露

Error: Security warning about hardcoded SECRET_KEY Source: Django deployment checklist Why It Happens: SECRET_KEY is in settings.py instead of environment variable or Secret Manager Prevention: Use
SECRET_KEY = os.environ.get('SECRET_KEY')
and set via
gcloud app deploy --set-env-vars
or Secret Manager.
错误信息:关于硬编码SECRET_KEY的安全警告 来源:Django部署检查清单 问题原因:SECRET_KEY写入settings.py而非环境变量或Secret Manager 解决方法:使用
SECRET_KEY = os.environ.get('SECRET_KEY')
,并通过
gcloud app deploy --set-env-vars
或Secret Manager设置

Issue #12: Cold Start Database Timeout

问题12:冷启动数据库超时

Error: First request after idle period times out Source: https://cloud.google.com/appengine/docs/standard/how-instances-are-managed Why It Happens: App Engine instance cold start + Cloud SQL activation delay (if using "on demand" activation) Prevention: Use App Engine warmup requests, or keep Cloud SQL instance "always on" (increases cost). Set
app_engine_apis: true
and add
/_ah/warmup
handler.

错误信息:闲置后的第一个请求超时 来源:https://cloud.google.com/appengine/docs/standard/how-instances-are-managed 问题原因:App Engine实例冷启动加上Cloud SQL激活延迟(如果使用“按需”激活) 解决方法:使用App Engine预热请求,或设置Cloud SQL实例为“始终运行”(会增加成本)。设置
app_engine_apis: true
并添加
/_ah/warmup
处理器

Configuration Files Reference

配置文件参考

settings.py (Complete Production Example)

settings.py(完整生产环境示例)

python
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent
python
import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

Security

Security

SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key-change-in-production') DEBUG = os.environ.get('DEBUG', 'False') == 'True' ALLOWED_HOSTS = [ '.appspot.com', '.run.app', 'localhost', '127.0.0.1', ]
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key-change-in-production') DEBUG = os.environ.get('DEBUG', 'False') == 'True' ALLOWED_HOSTS = [ '.appspot.com', '.run.app', 'localhost', '127.0.0.1', ]

CSRF for App Engine

CSRF for App Engine

CSRF_TRUSTED_ORIGINS = [ 'https://.appspot.com', 'https://.run.app', ]
CSRF_TRUSTED_ORIGINS = [ 'https://.appspot.com', 'https://.run.app', ]

Application definition

Application definition

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # Your apps here ]
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # Static files 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
ROOT_URLCONF = 'myproject.urls'
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
WSGI_APPLICATION = 'myproject.wsgi.application'
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # Your apps here ]
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # Static files 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
ROOT_URLCONF = 'myproject.urls'
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR / 'templates'], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
WSGI_APPLICATION = 'myproject.wsgi.application'

Database

Database

IS_APP_ENGINE = os.getenv('GAE_APPLICATION', None)
if IS_APP_ENGINE: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ['DB_NAME'], 'USER': os.environ['DB_USER'], 'PASSWORD': os.environ['DB_PASSWORD'], 'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}", 'PORT': '', 'CONN_MAX_AGE': 60, 'OPTIONS': { 'connect_timeout': 10, }, } } else: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DB_NAME', 'mydb'), 'USER': os.environ.get('DB_USER', 'postgres'), 'PASSWORD': os.environ.get('DB_PASSWORD', ''), 'HOST': os.environ.get('DB_HOST', '127.0.0.1'), 'PORT': os.environ.get('DB_PORT', '5432'), 'CONN_MAX_AGE': 60, } }
IS_APP_ENGINE = os.getenv('GAE_APPLICATION', None)
if IS_APP_ENGINE: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ['DB_NAME'], 'USER': os.environ['DB_USER'], 'PASSWORD': os.environ['DB_PASSWORD'], 'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}", 'PORT': '', 'CONN_MAX_AGE': 60, 'OPTIONS': { 'connect_timeout': 10, }, } } else: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DB_NAME', 'mydb'), 'USER': os.environ.get('DB_USER', 'postgres'), 'PASSWORD': os.environ.get('DB_PASSWORD', ''), 'HOST': os.environ.get('DB_HOST', '127.0.0.1'), 'PORT': os.environ.get('DB_PORT', '5432'), 'CONN_MAX_AGE': 60, } }

Static files

Static files

STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'static' STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
STATIC_URL = '/static/' STATIC_ROOT = BASE_DIR / 'static' STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Default primary key field type

Default primary key field type

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

Logging

Logging

LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'root': { 'handlers': ['console'], 'level': 'INFO', }, 'loggers': { 'django': { 'handlers': ['console'], 'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'), 'propagate': False, }, }, }
undefined
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'root': { 'handlers': ['console'], 'level': 'INFO', }, 'loggers': { 'django': { 'handlers': ['console'], 'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'), 'propagate': False, }, }, }
undefined

app.yaml (Complete Example)

app.yaml(完整示例)

yaml
runtime: python310
entrypoint: gunicorn -b :$PORT -w 2 -t 55 --threads 4 myproject.wsgi:application

instance_class: F2

env_variables:
  DB_NAME: "mydb"
  DB_USER: "postgres"
  CLOUD_SQL_CONNECTION_NAME: "project-id:us-central1:instance-name"
  DEBUG: "False"

beta_settings:
  cloud_sql_instances: "project-id:us-central1:instance-name"

handlers:
  - url: /static
    static_dir: static/
    secure: always

  - url: /.*
    script: auto
    secure: always

automatic_scaling:
  min_instances: 0
  max_instances: 2
  target_cpu_utilization: 0.65
Why these settings:
  • F2
    instance class allows 2 Gunicorn workers
  • min_instances: 0
    saves costs when idle
  • target_cpu_utilization: 0.65
    scales before overload
yaml
runtime: python310
entrypoint: gunicorn -b :$PORT -w 2 -t 55 --threads 4 myproject.wsgi:application

instance_class: F2

env_variables:
  DB_NAME: "mydb"
  DB_USER: "postgres"
  CLOUD_SQL_CONNECTION_NAME: "project-id:us-central1:instance-name"
  DEBUG: "False"

beta_settings:
  cloud_sql_instances: "project-id:us-central1:instance-name"

handlers:
  - url: /static
    static_dir: static/
    secure: always

  - url: /.*
    script: auto
    secure: always

automatic_scaling:
  min_instances: 0
  max_instances: 2
  target_cpu_utilization: 0.65
配置原因:
  • F2
    实例类型允许2个Gunicorn worker
  • min_instances: 0
    闲置时节省成本
  • target_cpu_utilization: 0.65
    在负载过高前自动扩容

requirements.txt

requirements.txt

Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0

Django>=5.1,<6.0
psycopg2-binary>=2.9.9
gunicorn>=23.0.0
whitenoise>=6.7.0

Common Patterns

常见模式

Pattern 1: Environment-Aware Database Configuration

模式1:环境感知的数据库配置

python
import os

def get_database_config():
    """Return database config based on environment."""
    is_production = os.getenv('GAE_APPLICATION', None)

    if is_production:
        return {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ['DB_NAME'],
            'USER': os.environ['DB_USER'],
            'PASSWORD': os.environ['DB_PASSWORD'],
            'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
            'PORT': '',
            'CONN_MAX_AGE': 60,
        }
    else:
        return {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ.get('DB_NAME', 'mydb'),
            'USER': os.environ.get('DB_USER', 'postgres'),
            'PASSWORD': os.environ.get('DB_PASSWORD', ''),
            'HOST': '127.0.0.1',
            'PORT': '5432',
            'CONN_MAX_AGE': 60,
        }

DATABASES = {'default': get_database_config()}
When to use: Standard Django project needing local/production parity
python
import os

def get_database_config():
    """Return database config based on environment."""
    is_production = os.getenv('GAE_APPLICATION', None)

    if is_production:
        return {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ['DB_NAME'],
            'USER': os.environ['DB_USER'],
            'PASSWORD': os.environ['DB_PASSWORD'],
            'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
            'PORT': '',
            'CONN_MAX_AGE': 60,
        }
    else:
        return {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': os.environ.get('DB_NAME', 'mydb'),
            'USER': os.environ.get('DB_USER', 'postgres'),
            'PASSWORD': os.environ.get('DB_PASSWORD', ''),
            'HOST': '127.0.0.1',
            'PORT': '5432',
            'CONN_MAX_AGE': 60,
        }

DATABASES = {'default': get_database_config()}
适用场景:需要本地/生产环境配置一致的标准Django项目

Pattern 2: Secret Manager Integration

模式2:Secret Manager集成

python
from google.cloud import secretmanager

def get_secret(secret_id, version_id='latest'):
    """Retrieve secret from Google Secret Manager."""
    client = secretmanager.SecretManagerServiceClient()
    project_id = os.environ.get('GOOGLE_CLOUD_PROJECT')
    name = f"projects/{project_id}/secrets/{secret_id}/versions/{version_id}"
    response = client.access_secret_version(request={"name": name})
    return response.payload.data.decode('UTF-8')
python
from google.cloud import secretmanager

def get_secret(secret_id, version_id='latest'):
    """Retrieve secret from Google Secret Manager."""
    client = secretmanager.SecretManagerServiceClient()
    project_id = os.environ.get('GOOGLE_CLOUD_PROJECT')
    name = f"projects/{project_id}/secrets/{secret_id}/versions/{version_id}"
    response = client.access_secret_version(request={"name": name})
    return response.payload.data.decode('UTF-8')

Usage in settings.py

Usage in settings.py

if os.getenv('GAE_APPLICATION'): SECRET_KEY = get_secret('django-secret-key') DB_PASSWORD = get_secret('db-password')

**When to use**: Production deployments requiring proper secret management
if os.getenv('GAE_APPLICATION'): SECRET_KEY = get_secret('django-secret-key') DB_PASSWORD = get_secret('db-password')

**适用场景**:需要完善密钥管理的生产环境部署

Pattern 3: Cloud SQL Python Connector (Alternative to Proxy)

模式3:Cloud SQL Python Connector(替代代理)

python
undefined
python
undefined

For local development without Cloud SQL Auth Proxy

For local development without Cloud SQL Auth Proxy

from google.cloud.sql.connector import Connector
def get_db_connection(): connector = Connector() return connector.connect( "project:region:instance", "pg8000", user="postgres", password=os.environ["DB_PASSWORD"], db="mydb", )
from google.cloud.sql.connector import Connector
def get_db_connection(): connector = Connector() return connector.connect( "project:region:instance", "pg8000", user="postgres", password=os.environ["DB_PASSWORD"], db="mydb", )

In settings.py for local dev (requires pg8000 driver)

In settings.py for local dev (requires pg8000 driver)

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydb', 'USER': 'postgres', 'OPTIONS': { 'get_conn': get_db_connection, }, } }

**When to use**: Local development when you can't install Cloud SQL Auth Proxy
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydb', 'USER': 'postgres', 'OPTIONS': { 'get_conn': get_db_connection, }, } }

**适用场景**:无法安装Cloud SQL Auth Proxy的本地开发环境

Pattern 4: Health Check Endpoint with Database Verification

模式4:带数据库验证的健康检查端点

python
undefined
python
undefined

views.py

views.py

from django.http import JsonResponse from django.db import connection
def health_check(request): """Health check endpoint for App Engine.""" try: with connection.cursor() as cursor: cursor.execute("SELECT 1") return JsonResponse({ 'status': 'healthy', 'database': 'connected', }) except Exception as e: return JsonResponse({ 'status': 'unhealthy', 'database': str(e), }, status=503)
from django.http import JsonResponse from django.db import connection
def health_check(request): """Health check endpoint for App Engine.""" try: with connection.cursor() as cursor: cursor.execute("SELECT 1") return JsonResponse({ 'status': 'healthy', 'database': 'connected', }) except Exception as e: return JsonResponse({ 'status': 'unhealthy', 'database': str(e), }, status=503)

urls.py

urls.py

urlpatterns = [ path('_ah/health', health_check, name='health_check'), ]

**When to use**: Load balancer health checks, monitoring database connectivity

---
urlpatterns = [ path('_ah/health', health_check, name='health_check'), ]

**适用场景**:负载均衡器健康检查、数据库连接状态监控

---

Using Bundled Resources

配套资源使用

Templates (templates/)

模板文件(templates/)

  • templates/settings_snippet.py
    - Copy-paste database configuration
  • templates/app.yaml
    - Complete App Engine configuration
  • templates/requirements.txt
    - Production dependencies
  • templates/settings_snippet.py
    - 可直接复制的数据库配置代码片段
  • templates/app.yaml
    - 完整的App Engine配置模板
  • templates/requirements.txt
    - 生产环境依赖项模板

References (references/)

参考文档(references/)

  • references/cloud-sql-proxy-setup.md
    - Detailed proxy installation and usage
  • references/iam-authentication.md
    - IAM-based authentication (no passwords)
  • references/secret-manager.md
    - Storing secrets properly
  • references/migrations-in-production.md
    - Running migrations safely
When Claude should load these:
  • Load
    cloud-sql-proxy-setup.md
    when user has local connection issues
  • Load
    iam-authentication.md
    when setting up passwordless auth
  • Load
    migrations-in-production.md
    before first production deployment

  • references/cloud-sql-proxy-setup.md
    - 详细的代理安装与使用指南
  • references/iam-authentication.md
    - 基于IAM的无密码认证方案
  • references/secret-manager.md
    - 安全的密钥存储方案
  • references/migrations-in-production.md
    - 生产环境安全执行迁移指南
何时加载这些资源:
  • 用户遇到本地连接问题时,加载
    cloud-sql-proxy-setup.md
  • 设置无密码认证时,加载
    iam-authentication.md
  • 首次生产部署前,加载
    migrations-in-production.md

Advanced Topics

进阶话题

IAM Database Authentication

IAM数据库认证

Instead of password authentication, use IAM for service-to-service auth:
bash
undefined
替代密码认证,使用IAM实现服务间认证:
bash
undefined

Enable IAM authentication on instance

Enable IAM authentication on instance

gcloud sql instances patch INSTANCE --database-flags cloudsql.iam_authentication=on
gcloud sql instances patch INSTANCE --database-flags cloudsql.iam_authentication=on

Create IAM user

Create IAM user

gcloud sql users create SERVICE_ACCOUNT@PROJECT.iam
--instance=INSTANCE
--type=CLOUD_IAM_SERVICE_ACCOUNT
gcloud sql users create SERVICE_ACCOUNT@PROJECT.iam
--instance=INSTANCE
--type=CLOUD_IAM_SERVICE_ACCOUNT

Grant connect permission

Grant connect permission

gcloud projects add-iam-policy-binding PROJECT
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com"
--role="roles/cloudsql.instanceUser"

**Django settings for IAM auth:**
```python
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ['DB_NAME'],
        'USER': f"{os.environ['SERVICE_ACCOUNT']}@{os.environ['PROJECT_ID']}.iam",
        'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
        'PORT': '',
        # No PASSWORD needed with IAM auth
    }
}
gcloud projects add-iam-policy-binding PROJECT
--member="serviceAccount:PROJECT@appspot.gserviceaccount.com"
--role="roles/cloudsql.instanceUser"

**IAM认证的Django设置**:
```python
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': os.environ['DB_NAME'],
        'USER': f"{os.environ['SERVICE_ACCOUNT']}@{os.environ['PROJECT_ID']}.iam",
        'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}",
        'PORT': '',
        # No PASSWORD needed with IAM auth
    }
}

Connection Pooling with PgBouncer

使用PgBouncer实现连接池

For high-traffic applications, deploy PgBouncer on Cloud Run:
yaml
undefined
对于高流量应用,在Cloud Run上部署PgBouncer:
yaml
undefined

Cloud Run service for PgBouncer

Cloud Run service for PgBouncer

See references/pgbouncer-setup.md for full configuration

See references/pgbouncer-setup.md for full configuration


**Why PgBouncer:**
- Cloud SQL limits connections (25-4000 depending on tier)
- Django's `CONN_MAX_AGE` helps but doesn't pool across processes
- PgBouncer provides true connection pooling

**使用PgBouncer的原因**:
- Cloud SQL有连接数限制(根据实例规格为25-4000)
- Django的`CONN_MAX_AGE`有帮助,但无法跨进程实现连接池
- PgBouncer提供真正的连接池功能

Running Migrations Safely

安全执行迁移

Option 1: Cloud Build (Recommended)
yaml
undefined
选项1:Cloud Build(推荐)
yaml
undefined

cloudbuild.yaml

cloudbuild.yaml

steps:
  • name: 'gcr.io/cloud-builders/gcloud' args: ['sql', 'connect', 'INSTANCE', '--quiet']
  • name: 'python:3.10' entrypoint: 'bash' args:
    • '-c'
    • | pip install -r requirements.txt python manage.py migrate --noinput env:
    • 'DB_NAME=mydb'
    • 'DB_USER=postgres'
    • 'DB_HOST=/cloudsql/PROJECT:REGION:INSTANCE' secretEnv: ['DB_PASSWORD']
availableSecrets: secretManager: - versionName: projects/PROJECT/secrets/db-password/versions/latest env: 'DB_PASSWORD'

**Option 2: Local with Proxy (Simple)**
```bash
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate

steps:
  • name: 'gcr.io/cloud-builders/gcloud' args: ['sql', 'connect', 'INSTANCE', '--quiet']
  • name: 'python:3.10' entrypoint: 'bash' args:
    • '-c'
    • | pip install -r requirements.txt python manage.py migrate --noinput env:
    • 'DB_NAME=mydb'
    • 'DB_USER=postgres'
    • 'DB_HOST=/cloudsql/PROJECT:REGION:INSTANCE' secretEnv: ['DB_PASSWORD']
availableSecrets: secretManager: - versionName: projects/PROJECT/secrets/db-password/versions/latest env: 'DB_PASSWORD'

**选项2:本地代理运行(简单)**
```bash
./cloud-sql-proxy PROJECT:REGION:INSTANCE &
python manage.py migrate

Dependencies

依赖项

Required:
  • Django>=5.1
    - Web framework
  • psycopg2-binary>=2.9.9
    - PostgreSQL adapter
  • gunicorn>=23.0.0
    - WSGI server for App Engine
Recommended:
  • whitenoise>=6.7.0
    - Static file serving
  • python-dotenv>=1.0.0
    - Local environment variables
Optional:
  • google-cloud-secret-manager>=2.20.0
    - Secret Manager integration
  • cloud-sql-python-connector[pg8000]>=1.12.0
    - Python-native Cloud SQL connector
  • django-db-connection-pool>=1.2.5
    - Connection pooling (alternative to CONN_MAX_AGE)

必需:
  • Django>=5.1
    - Web框架
  • psycopg2-binary>=2.9.9
    - PostgreSQL适配库
  • gunicorn>=23.0.0
    - App Engine的WSGI服务器
推荐:
  • whitenoise>=6.7.0
    - 静态文件托管
  • python-dotenv>=1.0.0
    - 本地环境变量管理
可选:
  • google-cloud-secret-manager>=2.20.0
    - Secret Manager集成
  • cloud-sql-python-connector[pg8000]>=1.12.0
    - Python原生Cloud SQL连接器
  • django-db-connection-pool>=1.2.5
    - 连接池(替代CONN_MAX_AGE)

Official Documentation

官方文档

Package Versions (Verified 2026-01-24)

包版本信息(2026-01-24验证)

json
{
  "dependencies": {
    "Django": ">=5.1,<6.0",
    "psycopg2-binary": ">=2.9.9",
    "gunicorn": ">=23.0.0",
    "whitenoise": ">=6.7.0"
  },
  "optional": {
    "google-cloud-secret-manager": ">=2.20.0",
    "cloud-sql-python-connector": ">=1.12.0"
  }
}

json
{
  "dependencies": {
    "Django": ">=5.1,<6.0",
    "psycopg2-binary": ">=2.9.9",
    "gunicorn": ">=23.0.0",
    "whitenoise": ">=6.7.0"
  },
  "optional": {
    "google-cloud-secret-manager": ">=2.20.0",
    "cloud-sql-python-connector": ">=1.12.0"
  }
}

Production Example

生产环境示例

This skill is based on production Django deployments on App Engine:
  • Use Case: Multi-tenant SaaS application
  • Traffic: 10K+ daily requests
  • Database: Cloud SQL PostgreSQL (db-g1-small, 25 connections)
  • Errors: 0 (all 12 known issues prevented)
  • Validation: Unix socket connection, connection pooling, static files, CSRF

本指南基于App Engine上的生产级Django部署实践:
  • 使用场景:多租户SaaS应用
  • 流量规模:每日10K+请求
  • 数据库:Cloud SQL PostgreSQL(db-g1-small,25个连接数)
  • 错误情况:0(所有12个已知问题均已预防)
  • 验证项:Unix套接字连接、连接池、静态文件、CSRF

Troubleshooting

故障排查

Problem:
No such file or directory
for socket

问题:套接字提示"找不到文件或目录"

Solution:
  1. Verify
    beta_settings.cloud_sql_instances
    in app.yaml
  2. Check connection name format:
    PROJECT:REGION:INSTANCE
  3. Ensure Cloud SQL instance exists:
    gcloud sql instances list
解决方法:
  1. 验证app.yaml中的
    beta_settings.cloud_sql_instances
    配置
  2. 检查连接名称格式:
    PROJECT:REGION:INSTANCE
  3. 确认Cloud SQL实例存在:
    gcloud sql instances list

Problem: Connection works locally but fails on App Engine

问题:本地连接正常但App Engine上连接失败

Solution:
  1. Verify
    HOST
    uses Unix socket path, not
    127.0.0.1
  2. Check environment variables are set in app.yaml
  3. Verify App Engine service account has
    Cloud SQL Client
    role
解决方法:
  1. 验证
    HOST
    使用Unix套接字路径而非
    127.0.0.1
  2. 检查app.yaml中环境变量是否正确设置
  3. 验证App Engine服务账号拥有
    Cloud SQL Client
    角色

Problem: Migrations timeout during deployment

问题:部署期间迁移超时

Solution:
  1. Don't run migrations in app.yaml entrypoint
  2. Use Cloud Build or run locally with proxy before deploying
  3. For large migrations, increase Cloud SQL tier temporarily
解决方法:
  1. 不要在app.yaml启动命令中运行迁移
  2. 使用Cloud Build或部署前通过本地代理运行迁移
  3. 对于大型迁移,临时升级Cloud SQL实例规格

Problem: Static files 404 after deploy

问题:部署后静态文件404

Solution:
  1. Run
    python manage.py collectstatic --noinput
    before deploy
  2. Verify
    static/
    handler in app.yaml points to correct directory
  3. Check WhiteNoise is in MIDDLEWARE list

解决方法:
  1. 部署前运行
    python manage.py collectstatic --noinput
  2. 验证app.yaml中的
    static/
    处理器指向正确目录
  3. 检查WhiteNoise是否在MIDDLEWARE列表中

Complete Setup Checklist

完整部署检查清单

  • Cloud SQL PostgreSQL instance created
  • Database and user created in Cloud SQL
  • Cloud SQL Auth Proxy installed locally
  • Django settings configured for Unix socket (production) and localhost (dev)
  • beta_settings.cloud_sql_instances
    in app.yaml
  • CONN_MAX_AGE
    set for connection pooling
  • Environment variables configured (DB_NAME, DB_USER, etc.)
  • DB_PASSWORD stored securely (not in app.yaml)
  • Static files collected and handler configured
  • CSRF_TRUSTED_ORIGINS includes *.appspot.com
  • Migrations run (locally with proxy) before first deploy
  • Deployed with
    gcloud app deploy
  • Verified database connection in production logs

Questions? Issues?
  1. Check the troubleshooting section above
  2. Verify all environment variables are set correctly
  3. Check official docs: https://cloud.google.com/python/django/appengine
  4. Ensure Cloud SQL instance is running:
    gcloud sql instances list

Last verified: 2026-01-24 | Skill version: 1.0.0
  • 已创建Cloud SQL PostgreSQL实例
  • 已在Cloud SQL中创建数据库和用户
  • 已在本地安装Cloud SQL Auth Proxy
  • 已配置Django设置以支持Unix套接字(生产)和localhost(开发)
  • app.yaml中已添加
    beta_settings.cloud_sql_instances
  • 已设置
    CONN_MAX_AGE
    实现连接池
  • 已配置环境变量(DB_NAME、DB_USER等)
  • DB_PASSWORD已安全存储(未写入app.yaml)
  • 已收集静态文件并配置处理器
  • CSRF_TRUSTED_ORIGINS已包含*.appspot.com
  • 已在首次部署前通过本地代理运行迁移
  • 已使用
    gcloud app deploy
    完成部署
  • 已在生产环境日志中验证数据库连接

有疑问?遇到问题?
  1. 查看上方故障排查章节
  2. 验证所有环境变量是否正确设置
  3. 查看官方文档:https://cloud.google.com/python/django/appengine
  4. 确认Cloud SQL实例处于运行状态:
    gcloud sql instances list

最后验证时间:2026-01-24 | 指南版本:1.0.0