Django仪表盘按类别、月份、年份过滤实现咨询
Django仪表盘数据过滤:后端vs前端实现方案
一、后端过滤(推荐大流量/敏感数据场景)
核心逻辑
前端提交过滤参数(类别、年份、月份),后端通过Django ORM或DataFrame预处理数据,只返回符合条件的结果给前端渲染图表。
优势
- 减少前端数据传输量,优化加载速度
- 敏感数据不会暴露到前端,安全性更高
- 利用数据库查询优化(如索引)提升过滤效率
代码实现
views.py(处理参数+过滤数据)
from django.shortcuts import render import pandas as pd from .models import YourDataModel # 替换为你的数据模型 def home(request): # 获取前端传递的过滤参数 category = request.GET.get('category', '') year = request.GET.get('year', '') month = request.GET.get('month', '') # 从数据库拉取数据并应用过滤 queryset = YourDataModel.objects.all() if category: queryset = queryset.filter(category=category) if year: queryset = queryset.filter(date__year=year) if month: queryset = queryset.filter(date__month=month) # 转换为DataFrame并转JSON df = pd.DataFrame(list(queryset.values())) data_json = df.to_json(orient='records') # 准备过滤选项(给前端下拉框) categories = YourDataModel.objects.values_list('category', flat=True).distinct() years = YourDataModel.objects.values_list('date__year', flat=True).distinct().order_by('-date__year') months = YourDataModel.objects.values_list('date__month', flat=True).distinct().order_by('date__month') return render(request, 'home.html', { 'data': data_json, 'categories': categories, 'years': years, 'months': months })
home.html(添加过滤表单)
<div class="filter-bar"> <select id="category-filter"> <option value="">所有类别</option> {% for cat in categories %} <option value="{{ cat }}">{{ cat }}</option> {% endfor %} </select> <select id="year-filter"> <option value="">所有年份</option> {% for year in years %} <option value="{{ year }}">{{ year }}</option> {% endfor %} </select> <select id="month-filter"> <option value="">所有月份</option> {% for month in months %} <option value="{{ month }}">{{ month }}</option> {% endfor %} </select> <button id="apply-filter">应用过滤</button> </div> <div id="chart-container"></div> <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> <script src="{% static 'js/home.js' %}"></script> <!-- 隐藏的全量数据容器 --> <script id="chart-data" type="application/json">{{ data|safe }}</script>
home.js(AJAX请求+更新图表)
document.addEventListener('DOMContentLoaded', () => { // 初始化图表 const initialData = JSON.parse(document.getElementById('chart-data').textContent); let chart = initChart(initialData); // 绑定过滤按钮事件 document.getElementById('apply-filter').addEventListener('click', () => { const params = new URLSearchParams({ category: document.getElementById('category-filter').value, year: document.getElementById('year-filter').value, month: document.getElementById('month-filter').value }); // 发起GET请求获取过滤后的数据 fetch(`/?${params}`) .then(res => res.json()) .then(filteredData => { updateChart(chart, filteredData); }); }); }); // 初始化图表 function initChart(data) { const ctx = document.getElementById('chart-container').getContext('2d'); return new Chart(ctx, { type: 'bar', data: { labels: data.map(item => item.date), datasets: [{ label: '数据统计', data: data.map(item => item.value), backgroundColor: 'rgba(75, 192, 192, 0.6)' }] } }); } // 更新图表数据 function updateChart(chart, newData) { chart.data.labels = newData.map(item => item.date); chart.data.datasets[0].data = newData.map(item => item.value); chart.update(); }
二、前端过滤(适合小数据量/实时交互场景)
核心逻辑
后端一次性返回全量数据,前端通过JS直接过滤数据后更新图表,无需请求后端。
优势
- 无后端请求延迟,交互更流畅
- 减少服务器请求压力
代码实现
views.py(仅返回全量数据)
from django.shortcuts import render import pandas as pd from .models import YourDataModel def home(request): queryset = YourDataModel.objects.all() df = pd.DataFrame(list(queryset.values())) data_json = df.to_json(orient='records') categories = YourDataModel.objects.values_list('category', flat=True).distinct() years = YourDataModel.objects.values_list('date__year', flat=True).distinct().order_by('-date__year') months = YourDataModel.objects.values_list('date__month', flat=True).distinct().order_by('date__month') return render(request, 'home.html', { 'data': data_json, 'categories': categories, 'years': years, 'months': months })
home.js(前端过滤逻辑)
document.addEventListener('DOMContentLoaded', () => { const fullData = JSON.parse(document.getElementById('chart-data').textContent); let chart = initChart(fullData); document.getElementById('apply-filter').addEventListener('click', () => { const category = document.getElementById('category-filter').value; const year = document.getElementById('year-filter').value; const month = document.getElementById('month-filter').value; // 前端过滤数据 let filteredData = fullData.filter(item => { const matchesCategory = !category || item.category === category; const matchesYear = !year || new Date(item.date).getFullYear().toString() === year; const matchesMonth = !month || (new Date(item.date).getMonth() + 1).toString() === month; return matchesCategory && matchesYear && matchesMonth; }); updateChart(chart, filteredData); }); }); // initChart和updateChart函数同后端过滤方案 function initChart(data) { const ctx = document.getElementById('chart-container').getContext('2d'); return new Chart(ctx, { type: 'bar', data: { labels: data.map(item => item.date), datasets: [{ label: '数据统计', data: data.map(item => item.value), backgroundColor: 'rgba(75, 192, 192, 0.6)' }] } }); } function updateChart(chart, newData) { chart.data.labels = newData.map(item => item.date); chart.data.datasets[0].data = newData.map(item => item.value); chart.update(); }
方案选择建议
- 选后端过滤:数据量大于1万条、包含敏感数据、需要利用数据库索引优化查询时
- 选前端过滤:数据量小于5000条、追求实时无刷新交互体验时
内容的提问来源于stack exchange,提问作者Gustavo Santos de Paula
相关产品推荐
相关产品推荐

