如何基于Flask与HTML在网页中展示Excel文件的指定工作表
问题描述
我正在用HTML和Flask搭建一个支持xlsx文件上传的网站,核心需求是查看文件里的工作表。目前已经实现了文件上传,并且把工作表名称输出到datalist中,现在需要实现选择目标工作表后在同一页面展示内容的功能,优先用Python实现,也可以结合JS,极端情况纯JS也可。
现有代码:
Python代码
from flask import Flask, render_template, request, jsonify from fileinput import filename import pandas as pd app = Flask(__name__) @app.route('/initialization', methods=['GET','POST']) def readfile(): file = request.files['file'] file.save(file.filename) data = pd.ExcelFile(file) return render_template('readfile.html',sheets = data.sheet_names) if __name__ == '__main__': app.run(debug=True)
HTML代码
<input type="text" name="sheet" list="sheet_list" placeholder="Choose sheet"> <datalist id="sheet_list"> {% for sheet in sheets %} <option>{{sheet}}</option> {% endfor %} </datalist>
解决方案
方案一:Flask后端主导实现(优先推荐)
通过表单提交选中的工作表名称,后端读取对应数据后渲染到页面,逻辑清晰且符合Python优先的要求。
1. 修改Flask后端代码
优化文件存储逻辑(避免同名文件覆盖),新增工作表查询路由:
from flask import Flask, render_template, request, session import pandas as pd import uuid import os app = Flask(__name__) app.secret_key = 'your_custom_secret_key' # 必须设置才能使用session UPLOAD_FOLDER = 'uploads' os.makedirs(UPLOAD_FOLDER, exist_ok=True) # 自动创建上传目录 # 首页:处理文件上传 @app.route('/', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': file = request.files['file'] if file.filename.endswith('.xlsx'): # 生成唯一文件名 unique_filename = f"{uuid.uuid4()}.xlsx" file_path = os.path.join(UPLOAD_FOLDER, unique_filename) file.save(file_path) # 存储文件路径到session,后续查询使用 session['file_path'] = file_path # 获取工作表名称 excel_data = pd.ExcelFile(file_path) return render_template('readfile.html', sheets=excel_data.sheet_names, sheet_data=None) return render_template('upload.html') # 处理工作表查询请求 @app.route('/show-sheet', methods=['POST']) def show_sheet(): file_path = session.get('file_path') if not file_path: return "请先上传文件", 400 sheet_name = request.form.get('sheet') # 读取工作表并转成HTML表格 df = pd.read_excel(file_path, sheet_name=sheet_name) df = df.fillna('') # 替换空值避免显示NaN sheet_html = df.to_html(classes='table table-striped', index=False) # 重新获取工作表名称,保持下拉列表可用 excel_data = pd.ExcelFile(file_path) return render_template('readfile.html', sheets=excel_data.sheet_names, sheet_data=sheet_html) if __name__ == '__main__': app.run(debug=True)
2. 新增上传页面(upload.html)
<!DOCTYPE html> <html> <head> <title>上传Excel文件</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-5"> <h3>上传XLSX文件</h3> <form method="POST" action="/" enctype="multipart/form-data" class="mt-3"> <div class="mb-3"> <input type="file" name="file" class="form-control" accept=".xlsx" required> </div> <button type="submit" class="btn btn-success">上传并查看工作表</button> </form> </div> </body> </html>
3. 修改readfile.html模板
添加表单提交按钮和内容展示区域:
<!DOCTYPE html> <html> <head> <title>查看Excel工作表</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-4"> <h3>选择工作表</h3> <form method="POST" action="/show-sheet"> <div class="mb-3"> <input type="text" name="sheet" list="sheet_list" placeholder="选择工作表" class="form-control" required> <datalist id="sheet_list"> {% for sheet in sheets %} <option value="{{ sheet }}">{{ sheet }}</option> {% endfor %} </datalist> </div> <button type="submit" class="btn btn-primary">查看工作表</button> </form> {% if sheet_data %} <div class="mt-4"> <h3>工作表内容:{{ request.form.sheet }}</h3> {{ sheet_data|safe }} </div> {% endif %} </div> </body> </html>
方案二:Flask + AJAX(无刷新展示)
如果需要页面不刷新就能展示内容,用JS发送AJAX请求后端获取数据,动态渲染到页面。
1. 后端新增API路由
在方案一的基础上,添加返回JSON数据的路由:
from flask import jsonify @app.route('/api/get-sheet', methods=['POST']) def get_sheet_api(): file_path = session.get('file_path') if not file_path: return jsonify({'error': '请先上传文件'}), 400 sheet_name = request.json.get('sheet') df = pd.read_excel(file_path, sheet_name=sheet_name) df = df.fillna('') return jsonify({ 'data': df.to_dict('records'), 'columns': df.columns.tolist() })
2. 修改readfile.html的前端逻辑
替换表单为无刷新交互:
<!DOCTYPE html> <html> <head> <title>查看Excel工作表</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <div class="container mt-4"> <h3>选择工作表</h3> <div class="mb-3"> <input type="text" id="sheetSelect" list="sheet_list" placeholder="选择工作表" class="form-control"> <datalist id="sheet_list"> {% for sheet in sheets %} <option value="{{ sheet }}">{{ sheet }}</option> {% endfor %} </datalist> <button id="showBtn" class="btn btn-primary mt-2">查看工作表</button> </div> <div id="sheetContent" class="mt-4"></div> </div> <script> document.getElementById('showBtn').addEventListener('click', function() { const sheetName = document.getElementById('sheetSelect').value; if (!sheetName) { alert('请选择工作表'); return; } fetch('/api/get-sheet', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({sheet: sheetName}) }) .then(res => res.json()) .then(data => { if (data.error) { alert(data.error); return; } // 动态生成表格 let tableHtml = `<h3>工作表内容:${sheetName}</h3><table class="table table-striped"><thead><tr>`; data.columns.forEach(col => tableHtml += `<th>${col}</th>`); tableHtml += `</tr></thead><tbody>`; data.data.forEach(row => { tableHtml += `<tr>`; data.columns.forEach(col => tableHtml += `<td>${row[col]}</td>`); tableHtml += `</tr>`; }); tableHtml += `</tbody></table>`; document.getElementById('sheetContent').innerHTML = tableHtml; }) .catch(err => { console.error(err); alert('加载工作表失败'); }); }); </script> </body> </html>
方案三:纯前端JS实现(极端场景)
无需后端,用SheetJS库在前端直接解析Excel文件:
<!DOCTYPE html> <html> <head> <title>前端解析Excel</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script> </head> <body> <div class="container mt-4"> <h3>上传并查看Excel工作表</h3> <div class="mb-3"> <input type="file" id="fileInput" accept=".xlsx" class="form-control"> </div> <div class="mb-3" id="sheetSelector" style="display: none;"> <input type="text" id="sheetSelect" list="sheet_list" placeholder="选择工作表" class="form-control"> <datalist id="sheet_list"></datalist> <button id="showBtn" class="btn btn-primary mt-2">查看工作表</button> </div> <div id="sheetContent" class="mt-4"></div> </div> <script> let workbook; // 解析上传的文件 document.getElementById('fileInput').addEventListener('change', function(e) { const file = e.target.files[0]; if (!file) return; const reader = new FileReader(); reader.onload = function(e) { workbook = XLSX.read(e.target.result, {type: 'binary'}); const sheetNames = workbook.SheetNames; // 填充工作表下拉列表 const datalist = document.getElementById('sheet_list'); datalist.innerHTML = sheetNames.map(name => `<option value="${name}">${name}</option>`).join(''); document.getElementById('sheetSelector').style.display = 'block'; }; reader.readAsBinaryString(file); }); // 展示选中的工作表 document.getElementById('showBtn').addEventListener('click', function() { const sheetName = document.getElementById('sheetSelect').value; if (!sheetName || !workbook) { alert('请先上传文件并选择工作表'); return; } const worksheet = workbook.Sheets[sheetName]; const data = XLSX.utils.sheet_to_json(worksheet, {header: 1}); // 生成表格HTML let tableHtml = `<h3>工作表内容:${sheetName}</h3><table class="table table-striped"><thead><tr>`; data[0].forEach(col => tableHtml += `<th>${col}</th>`); tableHtml += `</tr></thead><tbody>`; for (let i = 1; i < data.length; i++) { tableHtml += `<tr>`; data[i].forEach(cell => tableHtml += `<td>${cell || ''}</td>`); tableHtml += `</tr>`; } tableHtml += `</tbody></table>`; document.getElementById('sheetContent').innerHTML = tableHtml; }); </script> </body> </html>
内容的提问来源于stack exchange,提问作者Chārry
相关产品推荐
相关产品推荐

