Files
ZERO_CODE/export_meta_tables.py
2026-01-23 14:48:45 +08:00

216 lines
7.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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()