import json from pathlib import Path from django.core.management.base import BaseCommand, CommandError class Command(BaseCommand): help = "Render a .docx template by replacing placeholders like #{...} / {...} using a JSON context mapping." def add_arguments(self, parser): parser.add_argument( "template", type=str, help="模板文件路径(.docx),例如 /home/f/coding/flower/print-template.docx", ) parser.add_argument( "--out", type=str, default="rendered.docx", help="输出 docx 路径(默认 rendered.docx)", ) parser.add_argument( "--context-json", type=str, default="{}", help="JSON 字符串,键为占位符内部文本(例如 打印-销售单(8*9).客户名称)", ) parser.add_argument( "--context-json-file", type=str, default=None, help="JSON 文件路径(优先级高于 --context-json)", ) parser.add_argument( "--keep-unresolved", action="store_true", help="不清空未命中的占位符(默认会清空)", ) def handle(self, *args, **options): template = str(options["template"]) out = str(options["out"]) context_json = str(options["context_json"] or "{}") context_json_file = options.get("context_json_file") keep_unresolved = bool(options.get("keep_unresolved")) tp = Path(template) if not tp.exists(): raise CommandError(f"模板文件不存在:{template}") if tp.suffix.lower() != ".docx": raise CommandError("template 必须是 .docx 文件") if context_json_file: jp = Path(str(context_json_file)) if not jp.exists(): raise CommandError(f"JSON 文件不存在:{context_json_file}") context = json.loads(jp.read_text("utf-8")) else: context = json.loads(context_json) if not isinstance(context, dict): raise CommandError("context 必须是 JSON object(字典)") from printing.docx_template import render_docx_template stats = render_docx_template( template_path=str(tp), output_path=str(out), context=context, clear_unresolved=(not keep_unresolved), ) self.stdout.write( self.style.SUCCESS( f"渲染完成:out={out} paragraphs_touched={stats.paragraphs_touched} placeholders={stats.placeholders_replaced_or_cleared}" ) )