无REST API时Django转React前端及数据传递方法咨询
从Django模板迁移到React静态HTML的解决方案
结合你的场景(无独立服务器、最终输出静态HTML发邮件),核心思路是让Django负责数据处理,React负责UI渲染,最终生成纯静态的HTML文件。下面是具体的步骤和实现细节:
1. 数据传递:让Django把数据交给React
因为无法调用接口,所以需要在静态生成阶段把Django处理好的数据直接传递给React,有两种常用方式:
方式一:Django生成JSON数据文件
在Django中处理完数据后,将其序列化为JSON文件保存到指定目录,比如data/report_data.json:
# Django视图/脚本示例 import json from django.conf import settings import os def export_report_data(): # 处理数据生成tables、图表数据等 processed_data = { "tables": { "sales": [{"month": "Jan", "amount": 1200}, {"month": "Feb", "amount": 1800}], "active_users": [{"region": "North", "count": 500}, {"region": "South", "count": 300}] }, "chart_data": {"monthly_revenue": [1200, 1800, 1500, 2200]} } # 保存为JSON文件 output_path = os.path.join(settings.BASE_DIR, "data", "report_data.json") with open(output_path, "w") as f: json.dump(processed_data, f, indent=2)
方式二:Django直接将数据嵌入HTML模板
如果不需要单独的JSON文件,可以在Django模板中通过全局变量传递数据:
<!-- Django基础模板 --> <script> window.REPORT_DATA = {{ serialized_data|safe }}; </script>
其中serialized_data是Django视图中用json.dumps()处理后的字符串,加上|safe标签避免转义。
2. 模板转换:把Django模板语法转成React JSX
将你原有的Django模板逻辑,替换成React的组件式写法:
原Django模板片段
<div class="card"> {% for k, v in tables.items %} <div id="{{ k }}"> <h3>{{ k|title }}</h3> <table> {% for row in v %} <tr> {% for val in row.values %} <td>{{ val }}</td> {% endfor %} </tr> {% endfor %} </table> </div> {% endfor %} </div>
对应的React组件
import React from 'react'; // 接收Django传递的数据作为props function ReportCard({ tables }) { return ( <div className="card"> {/* 替换Django的{% for %}循环为Object.entries().map() */} {Object.entries(tables).map(([tableKey, tableRows]) => ( <div key={tableKey} id={tableKey}> {/* 替换Django的{{ k|title }}为JS字符串处理 */} <h3>{tableKey.charAt(0).toUpperCase() + tableKey.slice(1)}</h3> <table> <tbody> {tableRows.map((row, rowIndex) => ( <tr key={rowIndex}> {Object.values(row).map((cellVal, cellIndex) => ( <td key={cellIndex}>{cellVal}</td> ))} </tr> ))} </tbody> </table> </div> ))} </div> ); } export default ReportCard;
图表处理
如果原来Django用后端工具生成图表图片,现在可以用React的静态图表库(比如Recharts)直接基于数据渲染SVG图表,这样生成的HTML自带矢量图,邮件兼容性更好:
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; function RevenueChart({ data }) { // 格式化Django传递的图表数据为Recharts需要的结构 const chartData = data.map((value, index) => ({ month: ['Jan', 'Feb', 'Mar', 'Apr'][index], revenue: value })); return ( <div className="chart-container"> <h3>Monthly Revenue Trend</h3> <ResponsiveContainer width="100%" height={300}> <LineChart data={chartData}> <CartesianGrid strokeDasharray="3 3" /> <XAxis dataKey="month" /> <YAxis /> <Tooltip /> <Line type="monotone" dataKey="revenue" stroke="#2196F3" strokeWidth={2} /> </LineChart> </ResponsiveContainer> </div> ); }
3. 生成静态HTML:让React输出纯静态内容
因为邮件客户端大多禁用JavaScript,所以必须生成预渲染的纯静态HTML,不能依赖客户端React渲染。有两种实现方式:
方式一:用ReactDOMServer做服务器端渲染(SSR)
写一个Node.js脚本,读取Django生成的数据,用ReactDOMServer.renderToString()把组件渲染成HTML字符串:
const React = require('react'); const ReactDOMServer = require('react-dom/server'); const fs = require('fs'); const path = require('path'); const ReportCard = require('./src/components/ReportCard').default; const RevenueChart = require('./src/components/RevenueChart').default; // 读取Django生成的JSON数据 const dataPath = path.join(__dirname, 'data', 'report_data.json'); const reportData = JSON.parse(fs.readFileSync(dataPath, 'utf8')); // 渲染组件为HTML字符串 const renderedHTML = ReactDOMServer.renderToString( <div> <h1>Monthly Business Report</h1> <ReportCard tables={reportData.tables} /> <RevenueChart data={reportData.chart_data.monthly_revenue} /> </div> ); // 把渲染后的HTML插入到基础模板中 const baseTemplate = fs.readFileSync(path.join(__dirname, 'templates', 'base.html'), 'utf8'); const finalHTML = baseTemplate.replace('{{ react_content }}', renderedHTML); // 保存最终静态HTML fs.writeFileSync(path.join(__dirname, 'output', 'report.html'), finalHTML);
方式二:用Next.js静态导出
如果你的React应用较复杂,可以用Next.js的静态生成能力:
- 在Next.js页面中读取Django生成的JSON数据:
// pages/report.js import fs from 'fs/promises'; import path from 'path'; import ReportCard from '../components/ReportCard'; import RevenueChart from '../components/RevenueChart'; export async function getStaticProps() { const dataPath = path.join(process.cwd(), 'data', 'report_data.json'); const jsonData = await fs.readFile(dataPath, 'utf8'); const reportData = JSON.parse(jsonData); return { props: reportData }; } export default function ReportPage({ tables, chart_data }) { return ( <div> <h1>Monthly Business Report</h1> <ReportCard tables={tables} /> <RevenueChart data={chart_data.monthly_revenue} /> </div> ); }
- 运行
next build && next export,Next.js会自动生成纯静态的HTML文件到out目录。
4. 整合到django-bakery流程
把React静态生成的步骤加入到django-bakery的构建流程中:
- 在Django的构建脚本中,先调用数据导出函数生成JSON文件。
- 执行Node.js脚本或Next.js导出命令生成静态HTML。
- 把生成的HTML文件复制到django-bakery的输出目录,最终一起打包或发送邮件。
关键注意事项
- 邮件兼容性:尽量使用简单的HTML结构,优先用内联样式(避免外部CSS文件或
<style>标签),因为多数邮件客户端对复杂CSS支持有限。 - 依赖环境:需要在Django运行环境中安装Node.js和React相关依赖(比如
react、react-dom、recharts等)。 - 数据序列化:确保Django生成的JSON数据格式正确,处理好日期、特殊字符等,可通过
json.dumps(data, ensure_ascii=False)支持中文。
内容的提问来源于stack exchange,提问作者Claudiu Creanga
相关产品推荐
相关产品推荐

