单页面SPA数据查询web前端开发
1. 技术栈概述
-
后端:Python + Flask
-
Flask: 轻量级 Web 框架,用于处理 HTTP 请求、路由和渲染模板。
-
数据库连接库: 例如
psycopg2
(PostgreSQL),mysql-connector-python
(MySQL), 或sqlite3
(SQLite),用于直接执行 SQL 语句。 -
JSON: 用于将数据库查询结果从后端传送到前端,格式化为 JSON 数据。
-
-
前端:HTML + CSS + JavaScript
-
Bootstrap: 负责界面的布局、样式和组件(如表单、表格和导航)。
-
Jinja2: Flask 内置的模板引擎,用于渲染 HTML 页面。
-
JavaScript: 用于发送 AJAX 请求到后端,动态更新页面的查询结果表格。
-
2. 实现思路详解
后端:Flask + 传统 SQL
-
数据库连接管理:
-
在 Flask 应用中,你可以创建一个工具函数来管理数据库连接。比如,在每个请求开始时打开连接,请求结束后关闭连接,或者使用
g
对象来存储连接,确保在整个请求生命周期中只使用一个连接。
-
-
处理查询请求的路由:
-
为每一种查询(用户列表、销售信息等)创建不同的 Flask 路由(例如
/api/users
,/api/sales
)。 -
这些路由将接收来自前端的查询参数(比如日期范围、用户名)。
-
-
执行 SQL 查询:
-
在每个路由函数内部,根据接收到的参数,构建对应的 SQL 查询语句。注意: 为了防止 SQL 注入攻击,务必使用参数化查询(Parameterized Queries),而不是简单地将变量拼接到字符串中。
-
执行 SQL 语句,获取查询结果。
-
将查询结果(通常是元组或字典列表)转换为 JSON 格式,然后返回给前端。
-
后端代码示例(伪代码):
from flask import Flask, jsonify, request
import psycopg2 # 以 PostgreSQL 为例
import os
app = Flask(__name__)
# 一个简单的数据库连接管理函数
def get_db_connection():
conn = psycopg2.connect(os.environ['DATABASE_URL'])
return conn
@app.route('/api/users')
def get_users():
conn = get_db_connection()
cursor = conn.cursor()
# 从请求中获取参数,例如:username
username = request.args.get('username', '')
# 使用参数化查询来防止 SQL 注入
sql_query = "SELECT id, name, email FROM users WHERE name LIKE %s;"
cursor.execute(sql_query, (f"%{username}%",))
users = cursor.fetchall()
conn.close()
# 转换结果为字典列表并返回 JSON
user_list = [{"id": row[0], "name": row[1], "email": row[2]} for row in users]
return jsonify(user_list)
# 其他查询路由(/api/sales, /api/products 等)类似
前端:Bootstrap + AJAX
-
主页面布局:
-
在你的主 HTML 页面中,使用 Bootstrap 的组件来构建界面。
-
使用 表单 (
<form>
) 区域来放置不同的查询条件。 -
使用 Bootstrap 的 导航(Navs)或标签页(Tabs) 组件来切换不同的查询类型。
-
使用一个空的
<table>
元素或<div>
容器作为查询结果的占位符。
-
-
JavaScript 逻辑:
-
为每个查询表单或按钮添加事件监听器。
-
当用户提交表单或点击查询按钮时,阻止表单的默认提交行为。
-
收集表单中的查询参数。
-
使用 Fetch API 或 jQuery.ajax() 向对应的后端 API 路由发送一个异步的
GET
请求,并将查询参数附在 URL 中。 -
当后端返回 JSON 数据后,JavaScript 将解析这些数据。
-
动态地生成 HTML 表格行 (
<tr>
),将数据填充到表格中,并替换掉之前的结果。
-
前端代码示例(伪代码):
<div class="container">
<h2>数据查询中心</h2>
<ul class="nav nav-tabs" id="myTabs">
<li class="nav-item"><a class="nav-link active" data-bs-toggle="tab" href="#users-tab">用户查询</a></li>
<li class="nav-item"><a class="nav-link" data-bs-toggle="tab" href="#sales-tab">销售查询</a></li>
</ul>
<div class="tab-content mt-3">
<div class="tab-pane fade show active" id="users-tab">
<form id="user-search-form">
<input type="text" id="username-input" class="form-control" placeholder="输入用户名">
<button type="submit" class="btn btn-primary mt-2">查询用户</button>
</form>
<table class="table table-striped mt-4">
<thead>
<tr><th>ID</th><th>用户名</th><th>邮箱</th></tr>
</thead>
<tbody id="user-results-table-body">
</tbody>
</table>
</div>
</div>
</div>
<script>
document.getElementById('user-search-form').addEventListener('submit', function(event) {
event.preventDefault();
const username = document.getElementById('username-input').value;
fetch(`/api/users?username=${username}`)
.then(response => response.json())
.then(data => {
const tableBody = document.getElementById('user-results-table-body');
tableBody.innerHTML = ''; // 清空旧数据
data.forEach(user => {
const row = `<tr><td>${user.id}</td><td>${user.name}</td><td>${user.email}</td></tr>`;
tableBody.innerHTML += row;
});
})
.catch(error => console.error('Error:', error));
});
</script>
这种前后端分离、通过 API 交换数据的模式,能够很好地满足你的“单页面应用”需求,并且充分利用了 Flask 的简洁和 Bootstrap 的易用性。