尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

基于Django的汽车数据分析大屏可视化系统实战

发布时间:2026/9/29 7:20:00

资讯中心
01
ARTICLE

基于Django的汽车数据分析大屏可视化系统实战

基于Django的汽车数据分析大屏可视化系统实战
简介本资源是一套基于 Python 的汽车数据分析大屏可视化系统完整项目源码面向具备一定 Django 与 Vue 基础、希望练习前后端分离开发或搭建数据可视化大屏的开发者与学习者。项目采用 Vue 3 搭配 Vue-cli 构建前端界面借助 Echart 与 DataV 实现折线图、柱状图、饼图等图表的动态刷新渲染后端由 Django 处理业务逻辑与数据存储并配有 utils 工具函数、views 主结构组件、assets 样式资源及 common 中封装的 ECharts 与 flexible 屏幕适配代码目录划分清晰便于按模块阅读与二次开发。压缩包共约 2000 个文件以 md 文档、js 脚本、json 配置为主另含少量 py、xml、html 等整体约 73.95MB。目前已有 95 人学习下载适合作为课程设计、毕业设计或可视化练手项目的参考方案帮助读者快速理解大屏系统的整体架构与图表渲染思路。1. 从一堆 Excel 到能上墙的汽车数据大屏这套 Django 项目到底能跑出什么手里攥着几份 4S 店导出的销售流水、车型配置表和售后工单领导要你三天内搞出一个能挂在展厅电视上的实时看板——这种场景做过后端的人都懂纯前端堆 ECharts 只能做静态假数据真要把数据库里的销量、库存、投诉率跑通还是得有个 Django 在背后撑着。这套「基于 Django 汽车数据分析大屏可视化系统」解决的正是这件事它把 Django 的 ORM 查询、模板渲染和 WebSocket 推送串成一条线前端用大屏组件把汽车销量、品牌占比、区域分布、售后趋势几块图拼起来数据从模型层一路流到浏览器。适合谁刚学完 Django 教程想找个完整项目练手的或者手里有汽车行业数据、需要快速搭一个内部看板的从业者。它不是什么工业级 BI 平台但胜在结构清晰、能改能扩拿来当 django 项目实战新手的第一个完整交付物够用。2. 拆开这套 Django 汽车大屏模型、视图、通道三层怎么搭2.1 先看数据模型汽车销量、品牌、区域三张核心表怎么设计大屏能不能跑起来八成取决于模型设计得对不对。汽车数据分析的字段看着杂其实归拢下来就三块卖了多少销量、卖的什么车型/品牌、卖到哪区域/门店。我一般会先落三个模型别一上来就搞十几张表新手最容易犯的错就是表建太细结果 ORM 查询写成一团乱麻。# models.py from django.db import models class CarBrand(models.Model): 汽车品牌表大屏左上角品牌占比图的数据源 name models.CharField(max_length50, verbose_name品牌名称) country models.CharField(max_length30, verbose_name产地) class Meta: db_table car_brand class CarSale(models.Model): 销量流水表大屏核心按天/月/区域聚合都靠它 brand models.ForeignKey(CarBrand, on_deletemodels.CASCADE, verbose_name品牌) model_name models.CharField(max_length80, verbose_name车型) region models.CharField(max_length40, verbose_name销售区域) price models.DecimalField(max_digits10, decimal_places2, verbose_name成交价) sale_date models.DateField(verbose_name成交日期) quantity models.IntegerField(default1, verbose_name数量) class Meta: db_table car_sale indexes [models.Index(fields[sale_date, region])] # 大屏按时间区域查索引必须加逻辑说明CarBrand单独拆出来是为了品牌占比图能直接annotate聚合不用在流水表里反复distinct字符串。CarSale上的联合索引sale_date region是大屏性能的关键——大屏每隔几秒刷新一次没索引的话每次全表扫描数据量上到十万行浏览器就开始转圈。参数上price用DecimalField而不是FloatField金额计算别用浮点这是血泪经验聚合求和时浮点误差会让大屏数字对不上账。2.2 视图层怎么把 ORM 查询喂给大屏接口模型建好接下来是视图。大屏和普通页面不一样它要的是 JSON不是渲染好的 HTML。常见做法是写一组返回JsonResponse的接口每个图表一个接口前端各拿各的。这里用valuesannotate做聚合比在 Python 里循环算快一个量级。# views.py from django.db.models import Sum, Count from django.http import JsonResponse from .models import CarSale def brand_ratio(request): 品牌销量占比对应大屏环形图 data (CarSale.objects .values(brand__name) # 按品牌名分组 .annotate(totalSum(quantity)) # 聚合销量 .order_by(-total)[:10]) # 只取前10大屏放不下更多 return JsonResponse({ labels: [i[brand__name] for i in data], values: [i[total] for i in data], }) def region_trend(request): 区域销量趋势对应大屏折线图按月份聚合 data (CarSale.objects .values(region, sale_date__month) # 双字段分组 .annotate(totalSum(quantity)) .order_by(sale_date__month)) result {} for item in data: result.setdefault(item[region], []).append(item[total]) return JsonResponse(result)逻辑说明values(brand__name)里的双下划线是 Django ORM 跨表取字段的写法直接穿透外键拿到品牌名省掉一次select_related。annotate(Sum(...))生成的是GROUP BY语句数据库层面就算完了别在视图里for循环累加。[:10]这个切片很重要大屏环形图超过 10 个扇区就没法看了多的归到「其他」。region_trend里用sale_date__month做分组注意这只适合单年数据跨年要改成TruncMonth否则 2023 年 1 月和 2024 年 1 月会被合并——这个坑我在两个项目里都踩过。2.3 WebSocket 推送让大屏数据自己动起来静态接口靠前端定时器轮询也能用但轮询有个毛病数据没变也照查数据库压力白扛。热词里「python django websocket 实现后台有数据前端推送」说的就是更聪明的做法——用 Django Channels 建一条长连接后台数据一变就推。配置分三步装 channels、改 asgi、写 consumer。# consumers.py import json from channels.generic.websocket import AsyncWebsocketConsumer class SaleConsumer(AsyncWebsocketConsumer): async def connect(self): await self.channel_layer.group_add(sale_board, self.channel_name) await self.accept() async def disconnect(self, code): await self.channel_layer.group_discard(sale_board, self.channel_name) async def sale_update(self, event): # 收到 group_send 后推给浏览器 await self.send(text_datajson.dumps(event[data]))# settings.py 关键配置 INSTALLED_APPS [ daphne, # 必须放在 channels 前面否则 runserver 起不来 channels, # ... 其他 app ] ASGI_APPLICATION carboard.asgi.application CHANNEL_LAYERS { default: { BACKEND: channels_redis.core.RedisChannelLayer, CONFIG: {hosts: [(127.0.0.1, 6379)]}, } }逻辑说明group_add把每个连上来的浏览器加进sale_board这个组后台只要往组里group_send一条消息所有大屏同时更新。CHANNEL_LAYERS用 Redis 做后端是因为 Channels 默认的内存层只能单进程用一上多 worker 就丢消息。参数上daphne必须排在channels前面这是官方文档里一句话带过但新手必翻车的地方——顺序错了runserver直接报No application configured。数据写入侧在保存销量后调async_to_sync(channel_layer.group_send)触发推送这样大屏不用轮询也能秒级刷新。3. 从零把项目跑起来环境、建表、接口联调四步走3.1 环境依赖与 django 创建 app 的标准动作拿到源码包第一件事不是急着runserver而是把依赖对齐。这套项目跑在 Python 3.8 以上Django 版本看requirements.txt别自己乱升。我一般按这个顺序来能避开九成的环境报错。# 1. 建虚拟环境别用系统 Python 直接装 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 2. 装依赖 pip install -r requirements.txt # 3. 创建数据库表先确认 settings 里数据库配置 python manage.py makemigrations python manage.py migrate # 4. 建超级用户进后台录数据 python manage.py createsuperuser # 5. 起服务 python manage.py runserver 0.0.0.0:8000逻辑说明makemigrations生成迁移文件、migrate才真正建表这两步别搞混只跑migrate不改模型是不会建新表的。createsuperuser建完账号后进/admin把汽车品牌和销量数据录几条大屏才有东西显示。如果项目用了 Channels启动命令要换成daphne carboard.asgi:application或者装好 daphne 后照常用runserver但前提是INSTALLED_APPS顺序对。0.0.0.0:8000是为了让同局域网的其他机器也能访问大屏展厅电视往往不在开发机上。3.2 大屏前端怎么接后端接口前端大屏一般是独立的 HTML ECharts放在templates或static里。核心就一件事用fetch把刚才那几个 JSON 接口拉回来塞进 ECharts 的option。这里给一段能直接抄的骨架。// 品牌占比环形图 fetch(/api/brand_ratio/) .then(res res.json()) .then(data { const chart echarts.init(document.getElementById(brandChart)); chart.setOption({ series: [{ type: pie, radius: [40%, 70%], data: data.labels.map((name, i) ({ name, value: data.values[i] })) }] }); }); // WebSocket 实时更新销量数字 const ws new WebSocket(ws:// location.host /ws/sale/); ws.onmessage (e) { const msg JSON.parse(e.data); document.getElementById(totalSale).innerText msg.total; };逻辑说明fetch的路径要和urls.py里配的路由对上/api/brand_ratio/只是示例实际看项目路由。ECharts 的pie数据格式是{name, value}数组所以要把后端返回的两个平行数组zip起来。WebSocket 地址用location.host拼别写死127.0.0.1否则部署到服务器上大屏连不上。onmessage里更新 DOM 数字这就是「后台有数据前端推送」的落地形态——后台一group_send展厅大屏上的总销量数字立刻跳。3.3 数据导入把 Excel 灌进 Django 的两种路子真实项目里数据不会一条条手录多半是 Excel。两条路数据量小用admin批量导入插件数据量大写管理命令。我一般写命令可控。# management/commands/import_sales.py import csv from django.core.management.base import BaseCommand from carboard.models import CarSale, CarBrand class Command(BaseCommand): help 从 CSV 导入汽车销量数据 def handle(self, *args, **options): with open(sales.csv, encodingutf-8) as f: reader csv.DictReader(f) batch [] for row in reader: brand, _ CarBrand.objects.get_or_create(namerow[brand]) batch.append(CarSale( brandbrand, model_namerow[model], regionrow[region], pricerow[price], sale_daterow[date], quantityint(row[qty]), )) if len(batch) 1000: # 攒够1000条批量写 CarSale.objects.bulk_create(batch) batch [] if batch: CarSale.objects.bulk_create(batch) self.stdout.write(导入完成)逻辑说明get_or_create保证品牌不重复建返回的_是 created 标志用不上就丢掉。bulk_create是性能关键逐条save()导一万行要几分钟批量写几秒搞定。攒 1000 条一批是折中太大占内存太小失去批量意义。跑的时候python manage.py import_salesCSV 表头要和代码里的row[brand]对上对不上就报KeyError这是最常见的导入翻车点。4. 避坑与排查这套大屏最容易翻车的五个地方4.1 大屏刷新后数据不更新接口返回的是缓存现象改了数据库里的销量大屏刷新还是旧数字。原因多半是视图上挂了cache_page或者浏览器缓存了 GET 请求。解决接口视图去掉缓存装饰器或者给JsonResponse加Cache-Control: no-cache头前端fetch加{cache: no-store}。大屏数据要的是实时缓存在这里是负优化。4.2 WebSocket 连不上控制台报 404 或 500现象ws://连接直接失败Network 里看不到 101 切换协议。原因通常是routing.py里的路径和前端写的对不上或者ASGI_APPLICATION没配。解决检查routing.py的websocket_urlpatterns路径确认settings.py里ASGI_APPLICATION指向正确的 asgi 模块再确认启动用的是 daphne 而不是裸runserver没装 daphne 时 Channels 不会接管。4.3 聚合数字对不上账差几分钱现象大屏总销售额和财务给的数差几毛。原因price字段用了FloatField浮点累加有误差。解决模型里金额一律DecimalField聚合时用Sum(price, output_fieldDecimalField())前端展示再toFixed(2)。这个坑不排查业务方会一直质疑你的数据。4.4 数据量一大接口就超时现象几千行时秒回上到十万行接口转圈十几秒。原因聚合字段没索引或者values分组字段没走索引。解决给sale_date、region、brand这些高频分组字段加索引用explain()看 SQL 有没有走索引再不行就把聚合结果定时算好存进缓存表大屏直接读结果别每次实时算。4.5 部署到服务器后大屏白屏本地却正常现象本地跑得好好的一上服务器前端图表全空。原因多半是静态文件没收集或者接口跨域被拦。解决python manage.py collectstatic把静态文件收齐Nginx 配好static和media路径跨域的话在接口上加 CORS 头或者干脆前后端同域部署省掉跨域这档子事。5. 进阶把大屏做成能配置、能扩展的样子跑通基础版之后多数人会想两件事一是图表能不能不写死、让运营自己配二是权限能不能分销售看销售、售后看售后。这两块正好对应热词里的「大屏可视化编辑器」和「django rabc」。先说可配置。硬编码的图表位置和字段改一次就要动代码不现实。常见做法是把大屏布局抽成一张配置表每个图表存它的类型、数据接口、位置和尺寸前端读配置动态渲染。# models.py 追加 class ChartConfig(models.Model): 大屏图表配置运营在后台改前端动态渲染 title models.CharField(max_length60) chart_type models.CharField(max_length20, choices[ (pie, 环形图), (line, 折线图), (bar, 柱状图) ]) api_url models.CharField(max_length120, verbose_name数据接口) position_x models.IntegerField(default0) position_y models.IntegerField(default0) width models.IntegerField(default400) height models.IntegerField(default300) sort models.IntegerField(default0, verbose_name排序)逻辑说明api_url存接口路径前端拿到配置后按chart_type决定用哪种 ECharts 图按position_x/y绝对定位。这样加一块图不用改前端代码后台加条记录就行。sort控制渲染顺序避免图表叠在一起。这套思路就是轻量版的大屏可视化编辑器比上完整的拖拽编辑器省事得多中小项目够用。再说权限。Django 自带的auth够用但大屏场景往往要按角色控制「能看哪些图」。RBAC 的落地方式是在ChartConfig上加一个roles多对多字段视图里按当前用户角色过滤配置。# views.py def board_config(request): 按当前用户角色返回可见的图表配置 user_roles request.user.groups.values_list(name, flatTrue) configs (ChartConfig.objects .filter(roles__name__inuser_roles) # 只返回该角色可见的图 .distinct() .order_by(sort) .values(title, chart_type, api_url, position_x, position_y, width, height)) return JsonResponse({charts: list(configs)})逻辑说明request.user.groups拿当前用户所属角色组roles__name__in过滤出该角色能看的图表distinct()防止多角色用户拿到重复记录。前端拿到charts数组后循环echarts.init逐个渲染。这样销售登录只看到销量相关图售后登录只看到工单图一套大屏服务多个角色。验证这套配置有没有生效我一般走三步先在 admin 里给两个不同角色各配几块图再用两个账号分别登录看返回的charts数量对不对最后故意把某块图的api_url写错看前端是不是只挂那一块、其他图照常渲染——单块图失败不影响整屏这是大屏容错的基本要求。从那以后我每次交付大屏项目都会先把配置表和权限过滤跑通再填数据因为数据可以慢慢导架构错了返工成本太高。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。