136 lines
4.8 KiB
Python
136 lines
4.8 KiB
Python
"""gvsdsdk init — 子服务器快速初始化 SAAS 表
|
||
|
||
用法:
|
||
python manage.py gvsdsdk_init --db saas
|
||
python manage.py gvsdsdk_init --db saas --dry-run # 仅打印 SQL
|
||
python manage.py gvsdsdk_init --db default --modules auth,commission,payment
|
||
|
||
此命令会根据 gvsdsdk 中的模型定义,在指定数据库中创建对应的表。
|
||
适用于子服务器独立部署时快速建表。
|
||
"""
|
||
|
||
from django.core.management.base import BaseCommand, CommandError
|
||
from django.db import connections
|
||
from django.apps import apps
|
||
|
||
|
||
class Command(BaseCommand):
|
||
help = '初始化 gvsdsdk SAAS 表结构(子服务器建表工具)'
|
||
|
||
def add_arguments(self, parser):
|
||
parser.add_argument(
|
||
'--db', default='saas',
|
||
help='目标数据库别名(默认 saas)',
|
||
)
|
||
parser.add_argument(
|
||
'--dry-run', action='store_true',
|
||
help='仅打印建表 SQL,不执行',
|
||
)
|
||
parser.add_argument(
|
||
'--modules', default='all',
|
||
help='要初始化的模块,逗号分隔(all, auth, commission, payment)。默认 all',
|
||
)
|
||
|
||
def handle(self, *args, **options):
|
||
db_alias = options['db']
|
||
dry_run = options['dry_run']
|
||
modules_str = options['modules']
|
||
|
||
# 验证数据库连接
|
||
try:
|
||
connection = connections[db_alias]
|
||
except KeyError:
|
||
raise CommandError(f'数据库别名 "{db_alias}" 未配置,请在 DATABASES 中添加')
|
||
|
||
# 收集 gvsdsdk 模型
|
||
target_modules = self._parse_modules(modules_str)
|
||
models_to_create = self._collect_models(target_modules)
|
||
|
||
if not models_to_create:
|
||
self.stdout.write(self.style.WARNING('没有找到需要创建的模型'))
|
||
return
|
||
|
||
self.stdout.write(f'找到 {len(models_to_create)} 个模型:')
|
||
for model in models_to_create:
|
||
self.stdout.write(f' - {model.__name__} → {model._meta.db_table}')
|
||
|
||
# 生成建表 SQL
|
||
schema_editor = connection.schema_editor(collect_sql=True)
|
||
for model in models_to_create:
|
||
try:
|
||
schema_editor.create_model(model)
|
||
except Exception as e:
|
||
self.stdout.write(self.style.ERROR(f' 生成 {model.__name__} SQL 失败: {e}'))
|
||
|
||
sql_statements = schema_editor.collected_sql
|
||
|
||
if dry_run:
|
||
self.stdout.write(self.style.SUCCESS('\n=== DRY RUN: 建表 SQL ==='))
|
||
for sql in sql_statements:
|
||
self.stdout.write(sql)
|
||
self.stdout.write(self.style.SUCCESS(f'\n共 {len(sql_statements)} 条 SQL'))
|
||
return
|
||
|
||
# 执行建表
|
||
self.stdout.write(f'\n在数据库 "{db_alias}" 中创建表...')
|
||
try:
|
||
with connection.cursor() as cursor:
|
||
for sql in sql_statements:
|
||
cursor.execute(sql)
|
||
self.stdout.write(self.style.SUCCESS(f'成功创建 {len(sql_statements)} 个表'))
|
||
except Exception as e:
|
||
raise CommandError(f'建表失败: {e}')
|
||
|
||
def _parse_modules(self, modules_str):
|
||
if modules_str == 'all':
|
||
return {'auth', 'commission', 'payment'}
|
||
return set(m.strip() for m in modules_str.split(',') if m.strip())
|
||
|
||
def _collect_models(self, target_modules):
|
||
"""收集 gvsdsdk 中需要建表的模型"""
|
||
all_models = []
|
||
|
||
# 核心模型(auth 相关:User, Role, Permission, UserRole 等)
|
||
if 'auth' in target_modules:
|
||
try:
|
||
from gvsdsdk import models as core_models
|
||
for name in dir(core_models):
|
||
obj = getattr(core_models, name)
|
||
if self._is_qmodel(obj):
|
||
all_models.append(obj)
|
||
except Exception:
|
||
pass
|
||
|
||
# 分佣模型
|
||
if 'commission' in target_modules:
|
||
try:
|
||
from gvsdsdk.commission import models as comm_models
|
||
for name in dir(comm_models):
|
||
obj = getattr(comm_models, name)
|
||
if self._is_qmodel(obj):
|
||
all_models.append(obj)
|
||
except Exception:
|
||
pass
|
||
|
||
# 支付模型
|
||
if 'payment' in target_modules:
|
||
try:
|
||
from gvsdsdk.payment import models as pay_models
|
||
for name in dir(pay_models):
|
||
obj = getattr(pay_models, name)
|
||
if self._is_qmodel(obj):
|
||
all_models.append(obj)
|
||
except Exception:
|
||
pass
|
||
|
||
return all_models
|
||
|
||
def _is_qmodel(self, obj):
|
||
"""判断是否为 QModel 子类(非抽象)"""
|
||
from gvsdsdk.model_base import QModel
|
||
return (
|
||
isinstance(obj, type)
|
||
and issubclass(obj, QModel)
|
||
and not obj._meta.abstract
|
||
)
|