
简介本资源是一套完整的Python高分课程设计项目面向数据分析初学者、Web开发入门者及环境科学相关专业学生聚焦城市PM2.5空气质量的多维度可视化分析与Web化呈现。项目基于Django框架构建后端服务MySQL存储结构化数据集成时间序列、气象因子关联温度、湿度、风向、气压等、地域对比北上广成沈五城六年数据及季节/时段分布等10余类分析维度配套66个文件含17个核心Python模块含models、views、数据导入脚本、24个CSV实测数据集、3个HTML前端模板及部署文档等压缩包仅12.38MB轻量易部署。已有143人学习下载资源经作者实测可运行附详细部署文档与requirements依赖清单并提供SQL建库脚本及多城市原始数据小白替换数据即可本地启动目录结构清晰app01模块职责分明data与get_data子目录分别存放分析结果与原始采集逻辑便于理解项目架构与二次扩展。1. 项目缘起从数据孤岛到决策看板几年前我参与过一个环保部门的项目他们手头有大量从不同监测站点采集来的PM2.5数据格式不一有Excel有TXT甚至还有手写的记录本。每次领导要分析某个区域过去一年的污染趋势或者对比几个重点工业区的排放情况团队就得花上几天时间整理数据、画图、写报告。整个过程繁琐、低效而且不同人做的图表样式还不统一决策层很难快速、直观地获取有效信息。这其实就是很多传统数据管理面临的典型困境数据是“死”的分散在各个文件里无法实时、动态、交互式地呈现其背后的规律和价值。当时我们就决定用Python技术栈构建一个轻量级但功能完整的Web应用把数据“盘活”。Django作为成熟稳健的Web框架负责后端逻辑和业务处理MySQL作为关系型数据库负责结构化存储海量的时空监测数据而前端则通过数据可视化技术将枯燥的数字转化为直观的图表和地图形成一个可交互的“空气质量数据驾驶舱”。这个“城市PM2.5空气质量数据可视化分析系统”项目就是基于这样的实际需求诞生的。它不仅仅是一个学生作业或毕业设计更是一个具备企业级应用雏形的实战项目。通过它你可以系统地学习如何将Django、MySQL和数据可视化如ECharts、Pyecharts进行深度整合掌握从数据库设计、后端API开发、到前端图表渲染的全栈开发流程。无论你是想丰富自己的项目履历还是希望解决实际工作中的类似问题这个项目都能提供一条清晰的、可复现的实现路径。2. 核心架构设计为什么是Django MySQL ECharts在技术选型上我们放弃了Flask的极简也没有选择Spring Boot的“重量级”最终敲定Django MySQL ECharts的组合是基于以下几个核心考量2.1 Django为数据管理而生的“全家桶”Django的核心优势在于其“开箱即用”和“约定优于配置”的理念特别适合快速构建以数据管理为中心的应用。强大的ORM对象关系映射这是选择Django的首要原因。我们不需要手写复杂的SQL语句来操作数据库。只需要在models.py中定义如AirQualityData这样的Python类Django就能自动生成数据库表。查询数据就像操作Python列表一样简单例如AirQualityData.objects.filter(city北京, date__range(start_date, end_date))这极大地提升了开发效率和代码可读性也降低了SQL注入的风险。自带Admin管理后台对于PM2.5数据录入、修改、删除等日常管理操作Django Admin提供了一个功能完备、无需额外开发的后台界面。这对于项目初期数据导入和后期运维来说是一个巨大的生产力工具。清晰的项目结构Django的MVTModel-View-Template模式强制性地将数据模型、业务逻辑和页面展示分离使得项目结构清晰便于团队协作和后期维护。对于PM2.5分析系统我们可以清晰地划分出data_import数据导入、api数据接口、analysis数据分析等应用模块。2.2 MySQL结构化时空数据的可靠仓库PM2.5数据具有典型的时空属性每条记录都关联着具体的地点城市、监测站、具体的时间年、月、日、时以及具体的数值。MySQL作为最流行的开源关系型数据库是存储此类结构化数据的理想选择。数据一致性与完整性通过定义字段类型如DECIMAL存储浓度值DATETIME存储时间戳VARCHAR存储城市名和外键约束可以确保数据的准确性和关联性。高效的索引与查询我们会在city城市、date日期等常用查询字段上建立索引。当需要查询“上海市2023年全年PM2.5日均值”时索引能帮助数据库快速定位数据避免全表扫描这对于未来数据量增长到百万、千万级别时至关重要。成熟的生态与工具围绕MySQL有丰富的客户端工具如MySQL WorkbenchNavicat和运维方案便于数据的备份、迁移和性能监控。2.3 ECharts专业级可视化效果的保障前端可视化库有很多如D3.js功能强大但学习曲线陡峭Chart.js轻量但图表类型有限。我们选择百度开源的ECharts是因为它在功能丰富性和易用性之间取得了完美平衡。丰富的图表类型PM2.5分析需要折线图展示趋势、柱状图对比不同城市、地图展示空间分布、日历热力图展示全年每日情况等多种图表。ECharts对这些图表都有成熟、美观的实现。高度的可定制性从颜色主题、坐标轴样式到提示框内容、数据区域缩放ECharts几乎每个细节都可以通过配置项进行定制能够完美匹配专业数据分析报告的需求。与Python后端的无缝集成虽然ECharts是JavaScript库但我们可以通过两种方式与Django后端结合模板渲染在后端使用pyecharts库生成图表的HTML片段或配置项JSON直接嵌入到Django模板中。前后端分离Django后端提供纯净的RESTful API返回JSON数据前端通过Ajax获取数据后再用ECharts进行渲染。这种方式更现代前后端职责更清晰也是本项目推荐的方式。注意在实际企业环境中随着数据量增大和实时性要求提高架构可能会演进。例如引入Redis缓存高频查询的聚合结果如城市月度均值使用Celery异步处理耗时的数据清洗或模型分析任务甚至将大数据量的历史查询迁移到ClickHouse这类OLAP数据库中。但Django MySQL ECharts的组合是构建此类数据可视化分析平台最坚实、最通用的起点。3. 数据库模型设计与数据导入实战一个稳健的数据库设计是整个系统的基石。PM2.5数据看似简单但设计时需要考虑扩展性和查询效率。3.1 核心数据表设计我们设计了两张核心表一张存储监测站点信息一张存储具体的监测数据。这种设计符合数据库第三范式避免了数据冗余。# models.py from django.db import models class MonitoringSite(models.Model): 监测站点表 site_id models.CharField(max_length20, uniqueTrue, verbose_name站点编号) site_name models.CharField(max_length100, verbose_name站点名称) city models.CharField(max_length50, verbose_name所属城市) district models.CharField(max_length50, blankTrue, verbose_name所属区县) latitude models.FloatField(verbose_name纬度) longitude models.FloatField(verbose_name经度) address models.TextField(blankTrue, verbose_name详细地址) is_active models.BooleanField(defaultTrue, verbose_name是否启用) class Meta: db_table monitoring_site verbose_name 监测站点 verbose_name_plural verbose_name def __str__(self): return f{self.site_name} ({self.city}) class AirQualityData(models.Model): 空气质量数据表 site models.ForeignKey(MonitoringSite, on_deletemodels.CASCADE, related_nameair_data, verbose_name监测站点) timestamp models.DateTimeField(verbose_name监测时间) # 精确到小时或分钟 pm25 models.DecimalField(max_digits6, decimal_places2, verbose_namePM2.5浓度(μg/m³)) pm10 models.DecimalField(max_digits6, decimal_places2, blankTrue, nullTrue, verbose_namePM10浓度) so2 models.DecimalField(max_digits6, decimal_places2, blankTrue, nullTrue, verbose_name二氧化硫浓度) no2 models.DecimalField(max_digits6, decimal_places2, blankTrue, nullTrue, verbose_name二氧化氮浓度) co models.DecimalField(max_digits6, decimal_places2, blankTrue, nullTrue, verbose_name一氧化碳浓度) o3 models.DecimalField(max_digits6, decimal_places2, blankTrue, nullTrue, verbose_name臭氧浓度) aqi models.IntegerField(blankTrue, nullTrue, verbose_name空气质量指数) primary_pollutant models.CharField(max_length20, blankTrue, verbose_name首要污染物) level models.CharField(max_length20, blankTrue, verbose_name污染等级) class Meta: db_table air_quality_data verbose_name 空气质量数据 verbose_name_plural verbose_name # 联合唯一索引防止同一站点同一时间重复录入数据 unique_together [site, timestamp] # 索引加速按时间和站点的查询 indexes [ models.Index(fields[timestamp]), models.Index(fields[site, timestamp]), ] def __str__(self): return f{self.site.site_name} {self.timestamp}设计要点解析使用ForeignKey关联AirQualityData通过site字段关联到MonitoringSite。这样查询某个站点的所有历史数据或者通过站点找其所在城市都非常高效。DecimalField存储浓度值PM2.5浓度通常是浮点数使用DecimalField比FloatField更能保证计算精度避免浮点数误差在统计汇总时产生问题。unique_together联合唯一约束这是防止数据重复的关键。确保数据库不会存入同一站点、同一时刻的两条记录。合理使用索引在timestamp和(site, timestamp)上建立索引能极大优化按时间范围查询、按站点和时间查询的速度。3.2 数据导入从杂乱CSV到规整数据库原始数据往往来自环保部门公开的CSV或Excel文件格式可能不统一。我们需要一个健壮的导入脚本。# utils/data_importer.py import pandas as pd from django.utils.timezone import make_aware from datetime import datetime from .models import MonitoringSite, AirQualityData def import_air_quality_data(csv_file_path, city_name): 导入空气质量数据CSV文件 CSV列示例站点编号,监测时间,PM2.5,PM10,SO2,NO2,CO,O3,AQI,首要污染物,等级 df pd.read_csv(csv_file_path, encodinggbk) # 注意编码可能是gbk或utf-8 # 数据清洗与转换 df[监测时间] pd.to_datetime(df[监测时间]) # 处理可能的空值用None代替NaN以便Django ORM识别为NULL df df.where(pd.notnull(df), None) success_count 0 error_rows [] for index, row in df.iterrows(): try: # 1. 获取或创建监测站点 site, created MonitoringSite.objects.get_or_create( site_idrow[站点编号], defaults{ site_name: row.get(站点名称, f站点{row[站点编号]}), city: city_name, # 如果CSV不含经纬度可能需要从其他表关联或留空 latitude: 0.0, longitude: 0.0, } ) # 2. 创建数据记录使用make_aware处理时区 aware_time make_aware(row[监测时间]) # 检查是否已存在利用唯一约束但先查询避免异常 if not AirQualityData.objects.filter(sitesite, timestampaware_time).exists(): AirQualityData.objects.create( sitesite, timestampaware_time, pm25row[PM2.5], pm10row[PM10], so2row[SO2], no2row[NO2], corow[CO], o3row[O3], aqirow[AQI], primary_pollutantrow[首要污染物], levelrow[等级] ) success_count 1 else: print(f数据已存在跳过{site.site_name} - {aware_time}) except Exception as e: error_rows.append((index, str(e))) print(f导入第{index}行失败: {e}) continue print(f导入完成。成功{success_count}条失败{len(error_rows)}条。) if error_rows: print(失败行详情, error_rows) return success_count, error_rows实操心得数据导入是脏活累活但至关重要。务必做好异常捕获和日志记录。对于大规模历史数据导入可以考虑使用Django的bulk_create进行批量操作速度能提升数十倍。但要注意bulk_create会绕过模型的save()方法和信号signals如果业务逻辑依赖这些就需要谨慎处理。4. Django后端API开发构建高效数据服务我们采用前后端分离架构Django后端专注于提供纯净的数据API。这里我们使用Django REST Framework (DRF) 来快速构建强大的RESTful API。4.1 序列化器定义数据输出格式序列化器负责将复杂的模型实例转换为JSON等格式并处理反序列化验证和保存输入数据。# api/serializers.py from rest_framework import serializers from data.models import AirQualityData, MonitoringSite class MonitoringSiteSerializer(serializers.ModelSerializer): 监测站点序列化器 class Meta: model MonitoringSite fields [site_id, site_name, city, district, latitude, longitude] class AirQualityDataSerializer(serializers.ModelSerializer): 空气质量数据序列化器嵌套站点信息 site_info MonitoringSiteSerializer(sourcesite, read_onlyTrue) class Meta: model AirQualityData fields [id, timestamp, pm25, pm10, so2, no2, co, o3, aqi, primary_pollutant, level, site_info]4.2 视图集与过滤器实现灵活查询使用DRF的ModelViewSet和DjangoFilterBackend可以极简地实现增删改查和复杂过滤。# api/views.py from rest_framework import viewsets, filters from django_filters.rest_framework import DjangoFilterBackend from data.models import AirQualityData from .serializers import AirQualityDataSerializer from .filters import AirQualityDataFilter class AirQualityDataViewSet(viewsets.ModelViewSet): 空气质量数据API端点。 支持按城市、时间范围、污染物条件进行过滤。 支持分页。 queryset AirQualityData.objects.all().select_related(site) # 使用select_related优化查询避免N1问题 serializer_class AirQualityDataSerializer filter_backends [DjangoFilterBackend, filters.OrderingFilter] filterset_class AirQualityDataFilter # 自定义过滤器 ordering_fields [timestamp, pm25] ordering [-timestamp] # 默认按时间倒序排列 pagination_class PageNumberPagination # 启用分页 # api/filters.py import django_filters from data.models import AirQualityData class AirQualityDataFilter(django_filters.FilterSet): 自定义过滤器支持更复杂的查询 city django_filters.CharFilter(field_namesite__city, lookup_expriexact, label城市) start_date django_filters.DateTimeFilter(field_nametimestamp, lookup_exprgte, label开始时间) end_date django_filters.DateTimeFilter(field_nametimestamp, lookup_exprlte, label结束时间) pm25_min django_filters.NumberFilter(field_namepm25, lookup_exprgte, labelPM2.5最小值) pm25_max django_filters.NumberFilter(field_namepm25, lookup_exprlte, labelPM2.5最大值) class Meta: model AirQualityData fields [city, site]4.3 聚合数据API为可视化提供“加工后”的数据前端图表往往需要聚合后的数据如日均值、月均值、城市排名等。直接在数据库层面进行聚合比把所有数据传到前端再计算要高效得多。# api/views.py from rest_framework.views import APIView from rest_framework.response import Response from django.db.models import Avg, Max, Min, Count from django.db.models.functions import TruncDate, TruncMonth from data.models import AirQualityData class PM25TrendAPIView(APIView): 获取PM2.5趋势数据如近30天日均值。 前端请求示例GET /api/pm25_trend/?city北京days30 def get(self, request): city request.query_params.get(city) days int(request.query_params.get(days, 30)) from datetime import datetime, timedelta end_date datetime.now() start_date end_date - timedelta(daysdays) queryset AirQualityData.objects.filter( site__citycity, timestamp__range(start_date, end_date) ) # 按天聚合计算日均PM2.5 daily_data queryset.annotate( dateTruncDate(timestamp) # 将时间戳截断到日期 ).values(date).annotate( avg_pm25Avg(pm25), max_pm25Max(pm25), min_pm25Min(pm25) ).order_by(date) # 格式化数据供ECharts使用 trend_data { dates: [item[date].strftime(%Y-%m-%d) for item in daily_data], avg_pm25: [float(item[avg_pm25]) if item[avg_pm25] else None for item in daily_data], max_pm25: [float(item[max_pm25]) if item[max_pm25] else None for item in daily_data], min_pm25: [float(item[min_pm25]) if item[min_pm25] else None for item in daily_data], } return Response(trend_data) class CityRankingAPIView(APIView): 获取城市PM2.5平均浓度排名 def get(self, request): start_date request.query_params.get(start_date) end_date request.query_params.get(end_date) # 使用ORM进行分组聚合查询 city_avg AirQualityData.objects.filter( timestamp__range(start_date, end_date) ).values(site__city).annotate( avg_pm25Avg(pm25), data_countCount(id) ).filter(data_count__gt100) # 过滤掉数据量太少的城市结果更可靠 .order_by(avg_pm25) # 按平均浓度升序排列浓度越低越好 ranking_data [ {city: item[site__city], avg_pm25: float(item[avg_pm25])} for item in city_avg ] return Response(ranking_data)踩坑提醒在编写聚合API时务必注意数据库查询的性能。TruncDate、Avg等操作在数据量大时可能较慢。务必在timestamp和site__city等过滤字段上建立索引。对于非常复杂的聚合或实时性要求不高的数据可以考虑使用定时任务Celery预先计算好结果存入缓存Redis或单独的汇总表中API直接读取这是提升性能的常见做法。5. 前端可视化实现用ECharts绘制专业图表前端我们使用主流的Vue.js或React框架配合Axios调用后端API并使用ECharts进行绘图。这里以Vue3 ECharts为例。5.1 安装与基础集成# 在Vue项目中安装ECharts npm install echarts --save创建一个基础的折线图组件用于展示PM2.5趋势。!-- components/PM25TrendChart.vue -- template div refchartRef stylewidth: 100%; height: 400px;/div /template script setup import { ref, onMounted, onBeforeUnmount, watch } from vue; import * as echarts from echarts; import axios from axios; const props defineProps({ city: { type: String, required: true }, days: { type: Number, default: 30 } }); const chartRef ref(null); let chartInstance null; // 初始化图表 const initChart () { if (!chartRef.value) return; chartInstance echarts.init(chartRef.value); }; // 从后端API获取数据并渲染图表 const fetchDataAndRender async () { try { const response await axios.get(/api/pm25_trend/, { params: { city: props.city, days: props.days } }); const data response.data; renderChart(data); } catch (error) { console.error(获取PM2.5趋势数据失败:, error); // 可以在这里显示错误提示 } }; // 渲染图表 const renderChart (chartData) { if (!chartInstance) return; const option { title: { text: ${props.city}近${props.days}天PM2.5浓度趋势, left: center }, tooltip: { trigger: axis, formatter: function (params) { let result ${params[0].axisValue}br/; params.forEach(param { result ${param.seriesName}: ${param.value} μg/m³br/; }); return result; } }, legend: { data: [日均浓度, 最高浓度, 最低浓度], top: 30 }, grid: { left: 3%, right: 4%, bottom: 3%, containLabel: true }, xAxis: { type: category, boundaryGap: false, data: chartData.dates }, yAxis: { type: value, name: 浓度 (μg/m³), axisLabel: { formatter: {value} } }, series: [ { name: 日均浓度, type: line, smooth: true, data: chartData.avg_pm25, itemStyle: { color: #5470c6 }, lineStyle: { width: 3 } }, { name: 最高浓度, type: line, smooth: true, data: chartData.max_pm25, itemStyle: { color: #91cc75 }, lineStyle: { width: 1, type: dashed } }, { name: 最低浓度, type: line, smooth: true, data: chartData.min_pm25, itemStyle: { color: #fac858 }, lineStyle: { width: 1, type: dashed } } ] }; chartInstance.setOption(option); }; // 监听城市或天数变化重新获取数据 watch(() [props.city, props.days], () { fetchDataAndRender(); }); onMounted(() { initChart(); fetchDataAndRender(); // 监听窗口大小变化重绘图表 window.addEventListener(resize, () { chartInstance chartInstance.resize(); }); }); onBeforeUnmount(() { window.removeEventListener(resize, () { chartInstance chartInstance.resize(); }); chartInstance chartInstance.dispose(); }); /script5.2 实现地图可视化地图是展示空气质量空间分布最直观的方式。ECharts需要加载对应地区如中国的地图JSON文件。!-- components/AirQualityMap.vue -- template div refmapChartRef stylewidth: 100%; height: 500px;/div /template script setup import { ref, onMounted, onBeforeUnmount } from vue; import * as echarts from echarts; import axios from axios; // 需要额外安装中国地图数据 // npm install echarts/map/js/china // 或在index.html中通过script标签引入china.js import echarts/map/js/china; // 引入中国地图 const mapChartRef ref(null); let mapChartInstance null; const fetchCityAQIData async () { // 假设有一个API返回各城市最新的AQI或PM2.5数据 const response await axios.get(/api/latest_city_aqi/); return response.data; // 数据格式如[{city: 北京, value: 65}, {city: 上海, value: 48}, ...] }; const initMapChart async () { if (!mapChartRef.value) return; mapChartInstance echarts.init(mapChartRef.value); const mapData await fetchCityAQIData(); // 定义空气质量颜色区间 (根据AQI或PM2.5浓度) const visualMapPieces [ {min: 0, max: 35, label: 优, color: #93CE07}, {min: 35, max: 75, label: 良, color: #FBDB0F}, {min: 75, max: 115, label: 轻度污染, color: #FC7D02}, {min: 115, max: 150, label: 中度污染, color: #FD0100}, {min: 150, max: 250, label: 重度污染, color: #AA069F}, {min: 250, label: 严重污染, color: #AC3B2A} ]; const option { title: { text: 全国主要城市实时空气质量, subtext: 数据来源模拟数据, left: center }, tooltip: { trigger: item, formatter: function(params) { return ${params.name}br/AQI: ${params.value || N/A}; } }, visualMap: { type: piecewise, // 分段型视觉映射组件 pieces: visualMapPieces, left: left, top: bottom, textStyle: { color: #fff }, // 如果地图背景色深可以调整文字颜色 }, series: [{ name: AQI, type: map, map: china, roam: true, // 开启缩放和平移 zoom: 1.2, // 初始缩放级别 label: { show: true, fontSize: 10 }, emphasis: { // 高亮状态下的样式 label: { color: #fff, fontSize: 12 }, itemStyle: { areaColor: #ffefb8 // 高亮区域颜色 } }, data: mapData }] }; mapChartInstance.setOption(option); }; onMounted(() { initMapChart(); window.addEventListener(resize, () { mapChartInstance mapChartInstance.resize(); }); }); onBeforeUnmount(() { window.removeEventListener(resize, () { mapChartInstance mapChartInstance.resize(); }); mapChartInstance mapChartInstance.dispose(); }); /script经验技巧ECharts地图需要注册地理JSON数据。对于中国地图可以直接引入china.js。如果项目需要展示省、市级地图需要额外加载对应的JSON文件。地图数据通常较大可以考虑异步加载或使用CDN以避免影响页面首次加载速度。另外地图的颜色映射visualMap配置非常灵活可以根据业务需求如AQI六级标准精确设置颜色区间和标签这是让可视化结果专业化的关键。6. 系统部署与性能优化要点开发完成后将Django应用部署到生产环境是最后一步也是保证系统稳定、可用的关键。6.1 基础部署架构一个典型的部署架构如下Web服务器Gunicorn 或 uWSGI。它们作为应用服务器负责运行Django的Python代码。反向代理Nginx。负责处理静态文件CSS, JS, 图片、负载均衡并将动态请求转发给Gunicorn/uWSGI。数据库MySQL运行在独立的服务器或容器中。操作系统Linux如Ubuntu 20.04 LTS。6.2 关键部署步骤与配置收集静态文件Django的CSS、JS等需要由Nginx直接服务。python manage.py collectstatic这会将所有静态文件收集到STATIC_ROOT指定的目录如/var/www/myproject/static/。配置Gunicorn创建Gunicorn服务文件。# /etc/systemd/system/gunicorn.service [Unit] Descriptiongunicorn daemon for Django PM2.5 Project Afternetwork.target [Service] Userwww-data Groupwww-data WorkingDirectory/path/to/your/project ExecStart/path/to/venv/bin/gunicorn --access-logfile - --workers 3 --bind unix:/path/to/your/project/project.sock your_project.wsgi:application [Install] WantedBymulti-user.target--workers 3根据服务器CPU核心数调整通常建议2 * CPU核心数 1。--bind unix:...使用Unix socket与Nginx通信比TCP端口更快。配置Nginx# /etc/nginx/sites-available/your_project server { listen 80; server_name your_domain.com; # 或服务器IP location /favicon.ico { access_log off; log_not_found off; } location /static/ { alias /var/www/your_project/static/; expires 30d; } location /media/ { # 如果有用户上传的文件 alias /var/www/your_project/media/; expires 30d; } location / { include proxy_params; proxy_pass http://unix:/path/to/your/project/project.sock; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_redirect off; } }配置MySQL优化在/etc/mysql/my.cnf中调整一些基础参数以适应生产环境。[mysqld] innodb_buffer_pool_size 1G # 设置为系统内存的50%-70% max_connections 200 query_cache_type 0 # MySQL 8.0已移除查询缓存5.7可考虑关闭对于数据量大的表定期使用OPTIMIZE TABLE或ALTER TABLE ... ENGINEInnoDB进行碎片整理。6.3 性能优化实战数据库查询优化使用select_related和prefetch_related在DRF的ViewSet中通过重写get_queryset方法对关联查询进行优化避免N1查询问题。class AirQualityDataViewSet(viewsets.ModelViewSet): def get_queryset(self): return AirQualityData.objects.all().select_related(site)添加数据库索引如前所述在timestamp、site等常用查询字段上建立索引。可以使用Django的db_indexTrue或在Meta中使用indexes。限制查询集大小对于可能返回大量数据的API务必使用分页PageNumberPagination或LimitOffsetPagination。缓存策略视图缓存对于不经常变化且计算耗时的聚合数据API如城市月度排名可以使用Django的缓存框架。from django.views.decorators.cache import cache_page from rest_framework.decorators import api_view api_view([GET]) cache_page(60 * 60 * 6) # 缓存6小时 def city_monthly_ranking(request): # ... 复杂的聚合计算逻辑 return Response(data)模板片段缓存如果部分页面内容变化不频繁可以使用。使用Redis作为缓存后端安装django-redis性能远优于本地内存或文件缓存。前端资源优化压缩静态资源使用Webpack等工具对JS、CSS进行压缩和Tree Shaking。使用CDN将ECharts、Vue等公共库通过CDN引入减轻服务器压力加速用户加载。图片懒加载对于仪表盘中的图片资源使用懒加载。部署避坑指南静态文件404确保Nginx配置中的alias路径正确且STATIC_ROOT目录的权限允许Nginx进程通常是www-data用户读取。数据库连接失败检查Django的settings.py中DATABASES配置的HOST、PORT、USER、PASSWORD是否正确并确认MySQL用户有远程连接权限如果数据库不在本机。Gunicorn Worker崩溃检查Django代码中是否有内存泄漏或Worker数量是否设置过高导致内存不足。可以查看Gunicorn的错误日志/var/log/gunicorn/error.log。时区问题确保服务器、数据库和Django设置中的时区TIME_ZONE一致通常建议使用Asia/Shanghai避免时间显示错误。安全配置生产环境务必设置DEBUG False配置好ALLOWED_HOSTS使用HTTPS通过Nginx配置SSL证书并考虑使用环境变量管理敏感信息如数据库密码、Secret Key不要硬编码在代码中。本文还有配套的精品资源点击获取