"""一次性脚本:给已有的 site_nav_click 表加 anon_id 列(幂等,可重复执行)。 用法: PYTHONPATH=. python scripts/ensure_nav_click_anon_id.py """ import os import sqlite3 from app import app from applications.extensions import db with app.app_context(): uri = str(db.engine.url) if not uri.startswith('sqlite'): print('非 SQLite,跳过(MySQL 请用 flask db migrate/upgrade 或手工 ALTER TABLE)') raise SystemExit(0) # 注意:用 engine.url.database,而不是配置里的相对路径(配置可能是 sqlite:///../pear.db) path = db.engine.url.database or '' path = os.path.abspath(os.path.normpath(path)) print('DB:', path) conn = sqlite3.connect(path) cur = conn.cursor() cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='site_nav_click'") if not cur.fetchone(): print('表不存在,交给 db.create_all() 处理') conn.close() from applications.extensions import db from applications.models import NavClick # noqa: F401 db.create_all() print('OK: 已建表(含 anon_id)') raise SystemExit(0) cur.execute('PRAGMA table_info(site_nav_click)') cols = [r[1] for r in cur.fetchall()] print('现有列:', cols) if 'anon_id' in cols: print('OK: anon_id 已存在,无需变更') else: cur.execute("ALTER TABLE site_nav_click ADD COLUMN anon_id VARCHAR(36) DEFAULT ''") cur.execute('CREATE INDEX IF NOT EXISTS ix_site_nav_click_anon_id ON site_nav_click (anon_id)') conn.commit() print('OK: 已添加 anon_id 列 + 索引') cur.execute('PRAGMA table_info(site_nav_click)') print('变更后列:', [r[1] for r in cur.fetchall()]) conn.close()