ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Django+Pandas+ECharts:从零搭建数据分析可视化Web应用

Django+Pandas+ECharts:从零搭建数据分析可视化Web应用 做数据分析与可视化为什么我建议你先用 Django 而不是 Jupyter Notebook原因很简单Jupyter 适合自己探索数据但你要给业务方、给领导、给客户看结果时总不能丢一个.ipynb文件过去。你需要的是一个网页别人打开浏览器就能看到报表、能筛选条件、能看图表变化。这正好是 Web 框架的强项而 Django 又是 Python 生态里最成熟、资料最多、部署方案最完善的 Web 框架之一。这篇文章要解决的就是一个问题怎么用 Django 从零搭一个手机商品数据分析与可视化 Web 应用。你可以把它理解成一个简化版的数据报表后台数据源来自手机商品销售记录后台用 Pandas 做聚合统计前端用 ECharts 展示图表整个过程有完整的代码、可复制的命令和避坑说明。读完这篇文章你会得到三样东西一套能跑通的 Django 数据分析工程结构、一份从数据模型到图表渲染的完整代码、一份来自真实开发场景的排错清单。1. 这类项目真正的难点在哪很多人第一次做“Django 数据分析可视化”时会把注意力全放在图表库上ECharts 好看还是 Chart.js 好看大屏用哪个模板结果折腾了半天卡住的往往是更基础的问题数据存在哪里怎么设计表结构Django 的 ORM 查询结果怎么转成 JSON 给前端Pandas 算出来的 DataFrame 怎么和 Django 的 QuerySet 配合数据量一大页面加载变慢是 SQL 的问题还是图表渲染的问题这些才是实际项目里真正决定成败的环节。图表只是最后一步的呈现数据分析 Web 应用的核心是数据流从数据库到后端处理再到前端渲染每一步都要有清晰的数据格式约定。从架构层面看一个完整的 Django 数据分析项目通常分为四层层级职责对应技术数据层存储原始数据SQLite / MySQLDjango Model计算层聚合、清洗、统计分析Pandas、Django ORM接口层向前端提供结构化数据Django REST Framework / JsonResponse展示层图表、筛选条件、报表布局ECharts / Chart.js HTML/CSS你会发现数据分析的权限和增删改查没有本质区别都是数据输入和输出。区别在于数据分析项目对聚合查询和数据格式转换的要求更高而这恰好是新手最缺经验的地方。2. Django 做数据可视化核心概念与选型判断2.1 MTV 架构在数据分析场景下怎么理解Django 的 MTVModel-Template-View设计模式在数据分析项目里可以这样对应Model定义数据结构相当于数据分析里的“数据表”。View处理业务逻辑在数据分析项目里就是“数据加工和输出”的地方。Template负责页面渲染图表最终放在这里。URLconf路由分发决定用户访问哪个地址拿到什么结果。一个常见的数据分析请求是这样走的用户在页面上点击“按品牌查看销量”浏览器向 Django 发送请求URL 匹配到对应的 ViewView 通过 ORM 或 Pandas 从数据库查出数据数据整理成 JSON 返回给前端前端拿到 JSON 后渲染图表。这里新手容易犯的错是试图在 Template 里用 Django 模板语法直接画图表或者把数据处理逻辑全写在视图函数里。结果模板越来越乱视图越来越胖。正确做法是保持视图只负责准备数据模板只负责展示框架图表由 JavaScript 异步请求数据。2.2 为什么选 Pandas 而不是纯 ORMDjango 的 ORM 有aggregate和annotate能处理简单的分组统计。但如果要做透视表、滑动平均、分位数、复杂条件筛选、多表关联后的二次聚合ORM 写起来会非常绕。Pandas 的优势在于你只需要把 QuerySet 转成 DataFrame剩下的数据分析操作全部用 Pandas 完成代码更简洁、思路更清晰。# 直接用 ORM 做多字段分组统计 from django.db.models import Count, Sum data ( PhoneSale.objects .values(brand, region) .annotate(totalSum(amount)) .order_by(-total) )这个写法没问题但如果你接下来要算“每个品牌每个季度的环比增长率”ORM 就会变得很吃力。换成 Pandasimport pandas as pd df pd.DataFrame(list(PhoneSale.objects.values(brand, region, amount, sale_date))) df[quarter] df[sale_date].dt.to_period(Q) pivot df.pivot_table(indexquarter, columnsbrand, valuesamount, aggfuncsum) growth pivot.pct_change()代码量更少逻辑也更清晰。所以我的建议是简单统计用 ORM复杂分析用 Pandas两者结合才是最高效的姿势。2.3 图表库怎么选图表库优点缺点适合场景ECharts功能全、中文文档好、大屏效果强包体积大数据大屏、复杂图表Chart.js轻量、上手快功能相对基础管理后台、简单报表AntV G2可视化能力专业学习曲线较陡数据可视化专业团队如果只是做一个项目练手或给内部团队使用我更推荐 ECharts。原因不是它最强而是它的中文资料最多你遇到问题搜索时能更快找到答案。本文的完整示例也会用 ECharts。3. 环境准备与项目初始化3.1 环境清单开始之前请先确认你的电脑上有以下环境。版本号不写死以你本机实际安装为准建议使用较新的稳定版本Python 3.93.10、3.11、3.12 均可pip 包管理工具虚拟环境工具venv 或 conda一个趁手的 IDEPyCharm 或 VS Code 都行3.2 创建虚拟环境和安装依赖项目目录建议放在一个独立的文件夹里用虚拟环境隔离依赖。mkdir phone_data_analysis cd phone_data_analysis python -m venv venv # Windows 激活虚拟环境 venv\Scripts\activate # macOS / Linux 激活虚拟环境 source venv/bin/activate然后安装 Django、Pandas 和 Django REST Framework。数据分析项目里 DRF 不是必须的但它能让接口代码更规范后面我会说明理由。pip install django pandas djangorestframework为了后面演示方便再创建一个项目中存放生成模拟数据的脚本依赖pip install faker3.3 创建 Django 项目和应用这里有一个经验Django 项目的结构划分会影响后续扩展。建议把项目本身的业务逻辑和数据分析逻辑分开所以我创建两个 appanalysis数据分析、接口、可视化核心逻辑phones手机商品数据模型和数据管理。django-admin startproject config . python manage.py startapp phones python manage.py startapp analysis创建完成后的目录结构如下phone_data_analysis/ ├── config/ │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── phones/ │ ├── models.py │ ├── views.py │ └── ... ├── analysis/ │ ├── models.py │ ├── views.py │ └── ... ├── templates/ # 稍后手动创建 ├── static/ # 稍后手动创建 └── manage.py4. 数据模型设计以手机销售数据为例做数据分析前先得有数据。为了演示完整流程我们设计一个手机销售记录表包含品牌、型号、价格、销量、销售区域、销售日期等字段。这个结构足够典型既支持分组聚合也能做时间序列分析。打开phones/models.py写入以下代码# 文件路径phones/models.py from django.db import models class PhoneBrand(models.Model): 手机品牌表 name models.CharField(品牌名称, max_length50, uniqueTrue) country models.CharField(品牌国家, max_length50, blankTrue, default) class Meta: db_table phone_brand verbose_name 手机品牌 verbose_name_plural verbose_name def __str__(self): return self.name class PhoneSale(models.Model): 手机销售记录表 brand models.ForeignKey(PhoneBrand, on_deletemodels.CASCADE, verbose_name品牌) model_name models.CharField(手机型号, max_length100) price models.DecimalField(销售单价, max_digits10, decimal_places2) amount models.IntegerField(销售数量, default1) region models.CharField(销售区域, max_length50, db_indexTrue) sale_date models.DateField(销售日期, db_indexTrue) created_at models.DateTimeField(创建时间, auto_now_addTrue) class Meta: db_table phone_sale verbose_name 手机销售记录 verbose_name_plural verbose_name ordering [-sale_date] def __str__(self): return f{self.brand.name} {self.model_name}设计说明brand用外键关联品牌表避免在销售记录里重复维护品牌名称。price用DecimalField而不是FloatField因为金额数据用浮点数会出现精度问题这是数据分析里常见的坑。amount表示销量数据分析时通常要把“单价 × 数量”算成销售额。region和sale_date加db_index索引因为后续查询会频繁按照区域和日期分组。4.1 注册到 Django 后台Django 自带的后台管理系统非常适合数据维护和快速验证修改phones/admin.py# 文件路径phones/admin.py from django.contrib import admin from .models import PhoneBrand, PhoneSale admin.register(PhoneBrand) class PhoneBrandAdmin(admin.ModelAdmin): list_display (id, name, country) admin.register(PhoneSale) class PhoneSaleAdmin(admin.ModelAdmin): list_display (id, brand, model_name, price, amount, region, sale_date) list_filter (brand, region, sale_date) search_fields (model_name,)然后在config/settings.py的INSTALLED_APPS里注册两个 app# 文件路径config/settings.py INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, # 第三方应用 rest_framework, # 自建应用 phones, analysis, ]5. 生成模拟数据让项目先跑起来没有真实业务数据时我们用一个脚本往数据库里灌入模拟数据。注意实际项目中一定要保证数据来源合法合规本文只是在本地开发环境生成随机数据用于演示。在phones目录下新建一个services.py文件专门用于数据生成。这样做的好处是避免在视图里写一次性脚本逻辑。# 文件路径phones/services.py import random from datetime import date, timedelta from django.utils import timezone from faker import Faker from .models import PhoneBrand, PhoneSale fake Faker(zh_CN) def generate_sale_data(days180): 生成最近 days 天的手机销售模拟数据 brands list(PhoneBrand.objects.all()) if not brands: raise ValueError(请先创建品牌数据) regions [华北, 华东, 华南, 西南, 东北] for offset in range(days): sale_date date.today() - timedelta(daysoffset) # 每天生成 20 到 50 条记录 for _ in range(random.randint(20, 50)): brand random.choice(brands) record PhoneSale.objects.create( brandbrand, model_namef{brand.name} {fake.random_int(1000, 9999)}, pricefake.random_int(1999, 8999), amountfake.random_int(1, 10), regionrandom.choice(regions), sale_datesale_date, ) print(f数据生成完成共生成 {days * 35} 条左右的记录)为了测试方便把品牌初始化和数据生成整合到 Django 的 management command 里。在phones目录下创建management/commands/init_data.py# 文件路径phones/management/commands/init_data.py from django.core.management.base import BaseCommand from phones.models import PhoneBrand from phones.services import generate_sale_data class Command(BaseCommand): help 初始化手机品牌和模拟销售数据 def handle(self, *args, **options): # 初始化品牌 brands [华为, 小米, 苹果, OPPO, vivo] for name in brands: PhoneBrand.objects.get_or_create(namename, defaults{country: 中国}) # 苹果品牌补充产地信息 PhoneBrand.objects.filter(name苹果).update(country美国) self.stdout.write(self.style.SUCCESS(品牌初始化完成)) # 生成模拟销售数据 try: generate_sale_data(days180) self.stdout.write(self.style.SUCCESS(销售数据生成完成)) except Exception as e: self.stderr.write(self.style.ERROR(f数据生成失败{e}))执行数据库迁移和数据初始化python manage.py makemigrations python manage.py migrate python manage.py init_data这时打开 Django 自带后台的销售记录列表应该能看到大量模拟数据。6. 数据分析与可视化核心功能实现6.1 设计分析接口我先把核心分析功能分为四个维度品牌销量排行柱状图区域销售额分布饼图每日销售额趋势折线图品牌价格区间分布散点图创建analysis/views.py用 DRF 的api_view装饰器来约束接口只能接收 GET 请求并且返回 JSON。# 文件路径analysis/views.py import pandas as pd from django.db.models import Sum, F from django.utils.dateparse import parse_date from rest_framework.decorators import api_view from rest_framework.response import Response from phones.models import PhoneSale def _load_sale_dataframe(start_dateNone, end_dateNone): 从数据库加载销售数据并转换为 DataFrame queryset PhoneSale.objects.select_related(brand).all() if start_date: queryset queryset.filter(sale_date__gtestart_date) if end_date: queryset queryset.filter(sale_date__lteend_date) df pd.DataFrame( list(queryset.values( brand__name, model_name, price, amount, region, sale_date )) ) if df.empty: return df df.rename(columns{brand__name: brand}, inplaceTrue) df[price] df[price].astype(float) df[total_amount] df[price] * df[amount] df[sale_date] pd.to_datetime(df[sale_date]) return df api_view([GET]) def brand_sales(request): 品牌销量与销售额 df _load_sale_dataframe() if df.empty: return Response({data: [], message: 暂无数据}) result ( df.groupby(brand) .agg(total_sales(amount, sum), total_revenue(total_amount, sum)) .reset_index() .sort_values(total_revenue, ascendingFalse) ) data { brands: result[brand].tolist(), sales: result[total_sales].tolist(), revenue: result[total_revenue].round(2).tolist(), } return Response({data: data}) api_view([GET]) def region_sales(request): 区域销售额分布 df _load_sale_dataframe() if df.empty: return Response({data: [], message: 暂无数据}) result df.groupby(region)[total_amount].sum().reset_index() data { regions: result[region].tolist(), revenue: result[total_amount].round(2).tolist(), } return Response({data: data}) api_view([GET]) def daily_trend(request): 每日销售额趋势 raw_start request.query_params.get(start_date) raw_end request.query_params.get(end_date) start_date parse_date(raw_start) if raw_start else None end_date parse_date(raw_end) if raw_end else None df _load_sale_dataframe(start_date, end_date) if df.empty: return Response({data: [], message: 暂无数据}) result ( df.groupby(df[sale_date].dt.date)[total_amount] .sum() .reset_index() ) result.columns [date, revenue] data { dates: result[date].astype(str).tolist(), revenue: result[revenue].round(2).tolist(), } return Response({data: data})这里有一个容易忽略的性能问题_load_sale_dataframe每次接口调用都会把全表数据加载进内存数据量大时非常危险。改进方案是先用 Django ORM 做粗粒度过滤再交给 Pandas 处理。上面的代码已经做了这一步但这还不够更精细的优化会在最佳实践章节补充。6.2 配置 URL 路由创建analysis/urls.py# 文件路径analysis/urls.py from django.urls import path from . import views urlpatterns [ path(api/brand-sales/, views.brand_sales, namebrand-sales), path(api/region-sales/, views.region_sales, nameregion-sales), path(api/daily-trend/, views.daily_trend, namedaily-trend), ]然后在config/urls.py里把路由接入主应用# 文件路径config/urls.py from django.contrib import admin from django.urls import path, include from django.views.generic import TemplateView urlpatterns [ path(admin/, admin.site.urls), path(analysis/, include(analysis.urls)), # 首页直接展示可视化大屏 path(, TemplateView.as_view(template_namedashboard.html), namedashboard), ]6.3 配置模板和静态文件在项目根目录创建templates和static目录并在settings.py中配置# 文件路径config/settings.py import os TEMPLATES [ { BACKEND: django.template.backends.django.DjangoTemplates, DIRS: [os.path.join(BASE_DIR, templates)], APP_DIRS: True, OPTIONS: { context_processors: [ django.template.context_processors.debug, django.template.context_processors.request, django.contrib.auth.context_processors.auth, django.contrib.messages.context_processors.messages, ], }, }, ] STATIC_URL /static/ STATICFILES_DIRS [ os.path.join(BASE_DIR, static), ]为了引入 ECharts需要在templates/dashboard.html里使用 CDN 链接或者把 ECharts 的 JS 文件下载到static/js/目录下。生产环境更推荐把静态文件下载到本地避免外网 CDN 不稳定。创建templates/dashboard.html!-- 文件路径templates/dashboard.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title手机数据分析驾驶舱/title style body { font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif; background-color: #f5f7fa; margin: 0; padding: 20px; } .header { text-align: center; padding: 20px 0; } .header h1 { margin: 0; color: #333; font-size: 24px; } .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; max-width: 1280px; margin: 0 auto; } .card { background: #fff; border-radius: 8px; padding: 16px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .card h2 { font-size: 16px; color: #666; margin: 0 0 12px 0; } .chart { width: 100%; height: 380px; } /style /head body div classheader h1手机数据分析与可视化驾驶舱/h1 p演示数据仅用于技术学习/p /div div classgrid div classcard h2品牌销售额排行/h2 div idbrandChart classchart/div /div div classcard h2区域销售额分布/h2 div idregionChart classchart/div /div div classcard stylegrid-column: span 2; h2每日销售额趋势/h2 div idtrendChart classchart/div /div /div script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script script function fetchJson(url) { return fetch(url).then(res res.json()); } function initBrandChart() { const chart echarts.init(document.getElementById(brandChart)); fetchJson(/analysis/api/brand-sales/).then(data { const d data.data; chart.setOption({ tooltip: {}, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: d.brands }, yAxis: { type: value }, series: [{ name: 销售额, type: bar, data: d.revenue, itemStyle: { color: #5470c6 } }] }); }); } function initRegionChart() { const chart echarts.init(document.getElementById(regionChart)); fetchJson(/analysis/api/region-sales/).then(data { const d data.data; chart.setOption({ tooltip: { trigger: item }, series: [{ name: 区域销售额, type: pie, radius: 60%, data: d.regions.map((name, i) ({ name: name, value: d.revenue[i] })) }] }); }); } function initTrendChart() { const chart echarts.init(document.getElementById(trendChart)); fetchJson(/analysis/api/daily-trend/).then(data { const d data.data; chart.setOption({ tooltip: { trigger: axis }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, data: d.dates }, yAxis: { type: value }, series: [{ name: 每日销售额, type: line, smooth: true, data: d.revenue, areaStyle: {} }] }); }); } window.addEventListener(resize, () { const charts document.querySelectorAll(.chart); charts.forEach(item { const instance echarts.getInstanceByDom(item); if (instance) instance.resize(); }); }); initBrandChart(); initRegionChart(); initTrendChart(); /script /body /html7. 运行与效果验证启动 Django 开发服务器python manage.py runserver浏览器访问http://127.0.0.1:8000/如果一切正常你会看到一个包含三个图表的页面。验证重点品牌销售额排行是否按销售额降序排列。饼图是否展示五个区域的销售占比。折线图是否有 180 天的趋势数据且曲线平滑。如果页面显示空白按以下顺序排查打开浏览器开发者工具F12看 Console 有没有报错。直接访问http://127.0.0.1:8000/analysis/api/brand-sales/确认接口返回 JSON。检查 Django 终端日志看 500 错误的具体堆栈。接口返回的 JSON 格式类似如下{ data: { brands: [华为, 小米, 苹果, OPPO, vivo], sales: [5218, 4890, 4203, 3812, 3655], revenue: [21980006.0, 19623400.0, 18905630.0, 15829200.0, 15091200.0] } }到这里一个可以跑的 Django 手机数据分析与可视化项目已经完成。但真实项目不会止步于此下面这些经验才是让你从“跑得通”走向“能上线”的关键。8. 常见问题与排查思路问题现象可能原因排查方式解决方案页面能打开但图表空白接口 404 或返回格式不对F12 查看 Network 请求状态检查 URL 路由是否配置正确确认接口返回 JSON 结构接口报 500 错误且日志显示 “No module named pandas”虚拟环境未安装 pandas执行pip list查看包列表重新执行pip install pandas djangorestframework启动 runserver 时提示端口被占用8000 端口被其他进程占用lsof -i:8000macOS/Linux或 netstat -anofindstr 8000图表数据全是 0数据库里没有销售记录后台查看商品销售记录数执行python manage.py init_data重新生成模拟数据折线图日期显示乱码日期类型未转换检查接口返回的 dates 是否为字符串确保astype(str)转换后再返回数据量大时接口很慢全表扫描且 Pandas 加载全部数据开启 Django Debug SQL 日志增加 ORM 层粗过滤或分页加载数据还有几个容易踩的坑值得一提。第一Decimal 类型不能直接 JSON 序列化。如果 Django 的DecimalField没有先转成 float 或 strJsonResponse 会报错。本文的_load_sale_dataframe里已经做了astype(float)。第二时区设置会影响日期分组。如果settings.py中USE_TZ True而数据库存的又是 naive datetime按日期分组时可能产生偏移。建议在需要精确按天统计时统一用datetime.date类型存储日期。第三开发环境直接使用list(queryset)加载全表是示范代码。真实项目数据量达到几十万行时必须考虑分页、按需查询或利用数据库物化视图。9. 生产环境部署与工程化建议9.1 用 Gunicorn 替代 runserverDjango 自带的 runserver 是开发服务器性能差、安全性低。生产环境建议使用 GunicornLinux/macOS。pip install gunicorn gunicorn config.wsgi:application -b 0.0.0.0:8000 -w 4参数说明-w 4表示启动 4 个 worker 进程。具体数量可根据 CPU 核心数和内存调整。这里要特别提醒目录权限和进程用户要遵循最小权限原则不要为了省事直接用 root 运行 Web 服务。建议创建一个独立用户来运行 Django 应用和相关服务。9.2 数据访问安全边界数据分析系统最容易出现的数据安全问题是——接口未鉴权任何人都能通过 URL 直接拿到全部业务数据。对于内部报表系统至少要做到使用 Django 自带的login_required或者 DRF 的认证机制。接口层做权限校验不能只在前端隐藏入口。涉及敏感数据时数据库账号使用独立低权限账号不要用 root。9.3 数据库选型与迁移SQLite 适合开发环境和数据量小的场景。如果并发访问量大或数据规模增长尽早切到 MySQL 或 PostgreSQL。切换前先在测试环境验证备份现有数据。安装对应数据库驱动例如pip install mysqlclient或pip install psycopg2-binary。修改settings.py中的 DATABASES 配置。执行python manage.py migrate。用真实数据做一次全流程回归测试。9.4 缓存策略对于日报、周报这类不会频繁变化的数据可以加缓存。Django 的cache_page是性价比最高的方式。from django.views.decorators.cache import cache_page from django.utils.decorators import method_decorator cache_page(60 * 15) # 缓存 15 分钟 api_view([GET]) def brand_sales(request): ...使用缓存前务必想清楚一个问题数据多久更新一次能否接受最多 15 分钟的延迟。如果业务要求实时准确就不要随便加缓存否则会出现报表数据和实际数据不一致的麻烦。9.5 日志与监控数据分析项目上线后日志和监控不能省。建议至少做好三件事Django 的LOGGING配置里加上文件日志记录异常和慢接口。使用数据库慢查询日志定位超过阈值的 SQL。单独记录数据更新时间和数据量方便排查“为什么今天的报表数据不对”。10. 项目扩展方向当前项目已经跑通了数据分析可视化的完整链路接下来你可以往下面几个方向扩展添加筛选条件在页面加入日期范围、品牌、区域的下拉筛选前端通过 URL 参数传给后端接口。这个功能可以让你的项目从“展示固定报表”升级成“交互式分析工具”。增加导出功能使用 Pandas 的to_csv或to_excel方法给每个接口增加一个?exportcsv参数。业务方最喜欢的功能之一就是把报表导出成 Excel。接入更复杂的数据源将数据源从 SQLite 换成 MySQL 或 PostgreSQL或者直接读取 CSV、Excel、Kafka 等外部数据源。Django 本身不限制数据来源关键是做好数据接入层的抽象。改为异步任务如果数据处理量大、耗时长把分析逻辑放进 Celery 任务队列前端先显示“计算中”计算完成后再展示结果。这个改造会显著提升用户体验但复杂度也上升不少。构建可视化大屏ECharts 本身支持多图表联动和动态数据刷新配合 24 小时自动更新数据就能做成一个挂在办公室大屏上的实时数据驾驶舱。11. 结语回到最开始的问题为什么用 Django 做数据分析可视化我的判断是当数据分析的结果需要被其他人访问和使用时Web 化是必然选择而 Django 恰好是 Python 生态里 Web 化成本最低、最稳妥的方案。Pandas 负责数据加工Django 负责数据发布ECharts 负责数据呈现三者结合已经能覆盖绝大多数数据分析报告场景。这篇文章覆盖了从项目初始化、数据建模、数据生成、Pandas 分析、JSON 接口到 ECharts 渲染的完整链路也提到了实际部署时的权限、缓存、日志等工程问题。建议你先按步骤把演示项目跑通然后选择一个真实业务场景替换掉模拟数据亲手完成一次从数据到页面的全流程开发。关于更深入的内容建议继续学习 Django REST Framework 的序列化器、分页组件以及 Pandas 的透视表和重采样操作。再往后就是前端可视化技巧和数据大屏设计这些都属于可以长期投入的方向。代码已经放在文章中环境搭配起来很快建议收藏备用。如果你在运行时遇到问题欢迎在评论区把报错信息发出来一起讨论。
返回列表