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:
@@ -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
|
||||
@@ -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
@@ -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 = []
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user