216 lines
7.2 KiB
Python
216 lines
7.2 KiB
Python
import csv
|
||
import os
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
|
||
def init_django():
|
||
base_dir = Path(__file__).resolve().parent
|
||
project_root = base_dir / "ZeroCodeProject" / "apis" / "ZeroCodeMain"
|
||
if not project_root.exists():
|
||
return None
|
||
sys.path.insert(0, str(project_root))
|
||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ZeroCodeMain.settings")
|
||
try:
|
||
import django
|
||
|
||
django.setup()
|
||
from django.db import connection
|
||
from BaseApi.models import App, Model, ModelField, ModelSetting
|
||
except Exception:
|
||
return None
|
||
return App, Model, ModelField, ModelSetting, connection
|
||
|
||
|
||
def export_meta_tables(output_dir: str = None) -> None:
|
||
base_dir = Path(__file__).resolve().parent
|
||
if output_dir is None:
|
||
output_path = base_dir
|
||
else:
|
||
output_path = Path(output_dir)
|
||
output_path.mkdir(parents=True, exist_ok=True)
|
||
|
||
all_rows = []
|
||
|
||
table1 = [
|
||
["类名", "所在层/文件", "关键字段", "含义"],
|
||
["App", "BaseApi/models.py", "name, name_cn, module", "定义动态模型所属的应用和模块路径"],
|
||
["Model", "BaseApi/models.py", "app, name, name_cn", "定义单个动态模型的元数据(名称及所属应用)"],
|
||
["ModelField", "BaseApi/models.py", "model, name, type, is_show", "定义动态模型中的单个字段及其类型、显示属性"],
|
||
["ModelSetting", "BaseApi/models.py", "field, name, value", "定义字段的具体配置项(例如 max_length、null 等)"],
|
||
]
|
||
|
||
all_rows.append(["# 元数据类汇总表"])
|
||
all_rows.extend(table1)
|
||
all_rows.append([])
|
||
|
||
table2 = [
|
||
["元数据实体", "标识字段", "对应的原对象实体", "关系说明"],
|
||
["App 记录", "name", "Django 应用(AppConfig)", "确定动态模型注册的命名空间及表名前缀"],
|
||
["Model 记录", "app + name", "动态 Django 模型类 + 物理数据表", "每条 Model 记录对应一个模型类及一张数据表"],
|
||
["ModelField 记录", "model + name", "动态模型上的一个字段", "每条记录对应模型上的一个具体字段"],
|
||
["ModelSetting 记录", "field + name", "字段构造器上的一个关键字参数", "决定字段的单个具体属性(如 max_length、null 等)"],
|
||
]
|
||
|
||
all_rows.append(["# 元数据与原对象映射(概念层面)"])
|
||
all_rows.extend(table2)
|
||
all_rows.append([])
|
||
|
||
django_models = init_django()
|
||
if not django_models:
|
||
all_file = output_path / "meta_all_in_one.csv"
|
||
with all_file.open("w", newline="", encoding="utf-8-sig") as f:
|
||
writer = csv.writer(f)
|
||
writer.writerows(all_rows)
|
||
return
|
||
|
||
App, Model, ModelField, ModelSetting, connection = django_models
|
||
|
||
model_rows = [
|
||
[
|
||
"app_name",
|
||
"app_name_cn",
|
||
"app_module",
|
||
"model_name",
|
||
"model_name_cn",
|
||
"django_app_label",
|
||
"django_model_class",
|
||
"db_table_name",
|
||
]
|
||
]
|
||
|
||
for m in Model.objects.select_related("app").all():
|
||
app = m.app
|
||
django_app_label = app.name
|
||
django_model_class = django_app_label + "." + m.name
|
||
db_table_name = django_app_label + "_" + m.name
|
||
model_rows.append(
|
||
[
|
||
app.name,
|
||
app.name_cn,
|
||
app.module,
|
||
m.name,
|
||
m.name_cn,
|
||
django_app_label,
|
||
django_model_class,
|
||
db_table_name,
|
||
]
|
||
)
|
||
|
||
all_rows.append(["# 元数据模型与原对象模型一对一映射(实例层面)"])
|
||
all_rows.extend(model_rows)
|
||
all_rows.append([])
|
||
|
||
settings_map = {}
|
||
for s in ModelSetting.objects.select_related("field").all():
|
||
field_id = s.field_id
|
||
pair = s.name + "=" + s.value
|
||
settings_map.setdefault(field_id, []).append(pair)
|
||
|
||
field_rows = [
|
||
[
|
||
"app_name",
|
||
"model_name",
|
||
"field_name",
|
||
"field_name_cn",
|
||
"field_type",
|
||
"is_show",
|
||
"settings",
|
||
]
|
||
]
|
||
|
||
for f_obj in ModelField.objects.select_related("model", "model__app").all():
|
||
app = f_obj.model.app
|
||
model = f_obj.model
|
||
merged_settings = ";".join(settings_map.get(f_obj.id, []))
|
||
field_rows.append(
|
||
[
|
||
app.name,
|
||
model.name,
|
||
f_obj.name,
|
||
f_obj.name_cn,
|
||
f_obj.type,
|
||
"1" if f_obj.is_show else "0",
|
||
merged_settings,
|
||
]
|
||
)
|
||
|
||
all_rows.append(["# 字段级元数据与原对象字段映射(字段层面)"])
|
||
all_rows.extend(field_rows)
|
||
all_rows.append([])
|
||
|
||
table_rows = [["table_name", "model_class", "column_count"]]
|
||
model_map = {
|
||
"BaseApi_app": App,
|
||
"BaseApi_model": Model,
|
||
"BaseApi_modelfield": ModelField,
|
||
"BaseApi_modelsetting": ModelSetting,
|
||
}
|
||
for table_name, model_cls in model_map.items():
|
||
meta = model_cls._meta
|
||
concrete_fields = [f for f in meta.get_fields() if getattr(f, "concrete", False) and not getattr(f, "many_to_many", False)]
|
||
table_rows.append(
|
||
[
|
||
meta.db_table,
|
||
meta.label,
|
||
str(len(concrete_fields)),
|
||
]
|
||
)
|
||
|
||
all_rows.append(["# 元数据相关数据库表结构总览"])
|
||
all_rows.extend(table_rows)
|
||
all_rows.append([])
|
||
|
||
column_rows = [
|
||
["table_name", "model_class", "column_name", "field_type", "null", "primary_key", "default"]
|
||
]
|
||
for model_cls in [App, Model, ModelField, ModelSetting]:
|
||
meta = model_cls._meta
|
||
for field in meta.get_fields():
|
||
if not getattr(field, "concrete", False) or getattr(field, "many_to_many", False):
|
||
continue
|
||
default_value = field.default
|
||
if callable(default_value):
|
||
default_value = ""
|
||
column_rows.append(
|
||
[
|
||
meta.db_table,
|
||
meta.label,
|
||
field.name,
|
||
field.get_internal_type(),
|
||
"1" if field.null else "0",
|
||
"1" if field.primary_key else "0",
|
||
str(default_value),
|
||
]
|
||
)
|
||
|
||
all_rows.append(["# 元数据相关数据库字段结构明细"])
|
||
all_rows.extend(column_rows)
|
||
all_rows.append([])
|
||
|
||
for model_cls, section_title in [
|
||
(App, "# BaseApi_app 表数据"),
|
||
(Model, "# BaseApi_model 表数据"),
|
||
(ModelField, "# BaseApi_modelfield 表数据"),
|
||
(ModelSetting, "# BaseApi_modelsetting 表数据"),
|
||
]:
|
||
meta = model_cls._meta
|
||
field_names = [f.name for f in meta.fields]
|
||
rows = [field_names]
|
||
qs = model_cls.objects.all().values_list(*field_names)
|
||
for row in qs:
|
||
rows.append([str(v) for v in row])
|
||
all_rows.append([section_title])
|
||
all_rows.extend(rows)
|
||
all_rows.append([])
|
||
|
||
all_file = output_path / "meta_all_in_one.csv"
|
||
with all_file.open("w", newline="", encoding="utf-8-sig") as f:
|
||
writer = csv.writer(f)
|
||
writer.writerows(all_rows)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
export_meta_tables()
|
||
|