feat(settings): migrate db.sqlite3 to APPDATA dir, extract shared appdata.py

Migrate database path from project-local db.sqlite3 to %%APPDATA%%/TianXuan/ so data persists across updates.
- tianxuan/settings.py: DB path to APPDATA
- tianxuan/wsgi.py: use settings.DATABASES path instead of hardcoded db.sqlite3
- analysis/appdata.py: extract shared APPDATA path resolution
- analysis/session_store.py: use appdata.py for session store path
- analysis/views.py: use appdata.py for view paths

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
PM-pinou
2026-07-20 14:14:07 +08:00
parent 8fa36b774e
commit 0b6672781f
5 changed files with 58 additions and 17 deletions
+16
View File
@@ -0,0 +1,16 @@
"""跨模块共享的 %APPDATA% 路径工具"""
import os
from pathlib import Path
def get_appdata_dir() -> Path:
"""返回 %APPDATA%/TianXuan 目录路径(不保证存在)"""
appdata = os.environ.get('APPDATA', str(Path.home() / '.tianxuan'))
return Path(appdata) / 'TianXuan'
def ensure_appdata_dir() -> Path:
"""返回 %APPDATA%/TianXuan 目录路径(自动创建)"""
d = get_appdata_dir()
d.mkdir(parents=True, exist_ok=True)
return d
+2 -2
View File
@@ -52,8 +52,8 @@ def _get_store_path() -> Path:
Uses ``%APPDATA%/TianXuan/.session_store.json`` (Windows) or
``~/.tianxuan_session_store.json`` (other platforms).
"""
appdata = os.environ.get('APPDATA', os.path.expanduser('~'))
store_dir = Path(appdata) / 'TianXuan'
from analysis.appdata import get_appdata_dir
store_dir = get_appdata_dir()
store_dir.mkdir(parents=True, exist_ok=True)
return store_dir / '.session_store.json'
+2 -5
View File
@@ -317,11 +317,8 @@ def upload_csv(request):
return JsonResponse({'error': '总大小超过 50GB 限制'})
from django.utils import timezone
ts = timezone.now().strftime('%Y%m%d_%H%M%S')
import platform
if platform.system() == 'Windows':
base = Path(os.environ.get('APPDATA', '')) / 'TianXuan' / 'data' / 'uploads'
else:
base = Path.home() / '.tianxuan' / 'data' / 'uploads'
from analysis.appdata import ensure_appdata_dir
base = ensure_appdata_dir() / 'data' / 'uploads'
upload_dir = base / ts
upload_dir.mkdir(parents=True, exist_ok=True)
saved = []
+5 -1
View File
@@ -4,6 +4,10 @@ from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
os.makedirs(BASE_DIR / "logs", exist_ok=True)
# Application data directory (user data, outside project for clean updates)
_APP_DATA = Path(os.environ.get('APPDATA', str(Path.home() / '.tianxuan'))) / 'TianXuan'
_APP_DATA.mkdir(parents=True, exist_ok=True)
SECRET_KEY = "django-insecure-change-me-in-production"
DEBUG = True
@@ -60,7 +64,7 @@ WSGI_APPLICATION = "tianxuan.wsgi.application"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
"NAME": str(_APP_DATA / "db.sqlite3"),
'OPTIONS': {'timeout': 20},
}
}
+33 -9
View File
@@ -1,21 +1,31 @@
import os, sqlite3
from pathlib import Path
from django.core.wsgi import get_wsgi_application
db_path = Path(__file__).resolve().parent.parent / 'db.sqlite3'
if db_path.exists():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tianxuan.settings')
application = get_wsgi_application()
# ── DB integrity check ────────────────────────────────────────────
# Uses settings DB path (may be %APPDATA%/TianXuan/db.sqlite3)
from django.conf import settings
db_path = settings.DATABASES['default']['NAME']
if os.path.exists(db_path):
try:
conn = sqlite3.connect(str(db_path))
conn.execute('PRAGMA integrity_check')
conn.close()
except Exception:
import shutil
backup = Path(str(db_path) + '.corrupted')
import shutil, time
from django.core.management import call_command
backup = str(db_path) + f'.corrupted.{int(time.time())}'
shutil.copy2(str(db_path), str(backup))
db_path.unlink()
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tianxuan.settings')
application = get_wsgi_application()
os.remove(db_path)
call_command('migrate')
# Also ensure tls_ref_data table exists after fresh migration
try:
call_command('import_tlsdb')
except Exception:
pass
# ── startup recovery ────────────────────────────────────────────────
# Restore previously uploaded datasets whose CSV files still exist.
@@ -27,3 +37,17 @@ try:
logging.getLogger('django').info('Restored %d datasets from disk', count)
except Exception:
pass
# ── ensure tls_ref_data table ────────────────────────────────────
# Newly created databases won't have this table yet.
try:
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT 1 FROM tls_ref_data LIMIT 1")
except Exception:
# Table doesn't exist — import it
try:
from django.core.management import call_command
call_command('import_tlsdb')
except Exception:
pass