Flask - SQLite
Flask – 使用 SQLite 数据库
Section titled “Flask – 使用 SQLite 数据库”SQLite 是一种轻量级、基于文件的关系型数据库。Python 通过 sqlite3 模块内置了对 SQLite 的支持,这使得它易于与 Flask 应用集成,尤其适用于较小的项目或原型。
首先,让我们创建一个简单的脚本(init_db.py)来设置我们的 SQLite 数据库文件(database.db)并创建一个名为 students 的表。
import sqlite3
# 连接到数据库文件(如果不存在则创建)conn = sqlite3.connect('database.db')print("Opened database successfully")
# 创建 students 表conn.execute('''CREATE TABLE IF NOT EXISTS students ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, addr TEXT, city TEXT, pin TEXT);''')print("Table created successfully or already exists")
# 关闭连接conn.close()从你的终端运行一次此脚本:python init_db.py
具有数据库交互的 Flask 应用
Section titled “具有数据库交互的 Flask 应用”现在,让我们构建一个 Flask 应用(app.py)来与此数据库交互。我们将创建路由来:
- 显示添加新学生的表单。
- 处理表单提交,将学生添加到数据库。
- 列出数据库中当前所有学生。
数据库连接的辅助函数
Section titled “数据库连接的辅助函数”拥有一个用于获取数据库连接的辅助函数是一个好习惯。这确保了一致性。
import sqlite3
def get_db_connection(): conn = sqlite3.connect('database.db') # 将行返回为字典样式的对象 conn.row_factory = sqlite3.Row return conn设置 conn.row_factory = sqlite3.Row 允许你按名称(例如 row['name'])而不是仅按索引(row[0])访问列,这使代码更具可读性。
Flask 应用代码(app.py):
Section titled “Flask 应用代码(app.py):”from flask import Flask, render_template, request, url_for, flash, redirectimport sqlite3import sys # 用于错误打印
app = Flask(__name__)# 消息闪现所需app.config['SECRET_KEY'] = 'your secret key here'
def get_db_connection(): conn = sqlite3.connect('database.db') conn.row_factory = sqlite3.Row return conn
@app.route('/')def index(): conn = get_db_connection() students = conn.execute('SELECT * FROM students').fetchall() conn.close() return render_template('index.html', students=students)
@app.route('/new', methods=('GET', 'POST'))def new_student(): if request.method == 'POST': name = request.form['name'] addr = request.form['addr'] city = request.form['city'] pin = request.form['pin']
if not name: flash('Name is required!', 'error') else: conn = get_db_connection() try: conn.execute('INSERT INTO students (name, addr, city, pin) VALUES (?, ?, ?, ?)', (name, addr, city, pin)) conn.commit() flash('Student added successfully!', 'success') except sqlite3.Error as e: print(f"Database error: {e}", file=sys.stderr) flash(f'Error adding student: {e}', 'error') conn.rollback() # 回滚错误时的更改 finally: conn.close() # 添加成功/失败后重定向到主页 return redirect(url_for('index'))
# 如果是 GET 请求,只显示表单 return render_template('new_student.html')
if __name__ == '__main__': app.run(debug=True)我们需要三个 HTML 模板,放在一个名为 templates 的文件夹中:
index.html(显示列表并提供添加新学生的链接)
Section titled “index.html(显示列表并提供添加新学生的链接)”<!DOCTYPE html><html><head> <title>Student List</title> <style> .alert { padding: 15px; margin-bottom: 20px; border: 1px solid transparent; border-radius: 4px; } .alert-success { color: #155724; background-color: #d4edda; border-color: #c3e6cb; } .alert-error { color: #721c24; background-color: #f8d7da; border-color: #f5c6cb; } table, th, td { border: 1px solid black; border-collapse: collapse; padding: 5px; } th { background-color: #f2f2f2; } </style></head><body> <h1>学生记录</h1>
<!-- Display flashed messages --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} <div class="alert alert-{{ category }}">{{ message }}</div> {% endfor %} {% endif %} {% endwith %}
<p><a href="{{ url_for('new_student') }}">添加新学生</a></p>
<table> <thead> <tr> <th>ID</th> <th>姓名</th> <th>地址</th> <th>城市</th> <th>邮编</th> </tr> </thead> <tbody> {% for student in students %} <tr> <td>{{ student['id'] }}</td> <td>{{ student['name'] }}</td> <td>{{ student['addr'] }}</td> <td>{{ student['city'] }}</td> <td>{{ student['pin'] }}</td> </tr> {% else %} <tr> <td colspan="5">未找到学生记录。</td> </tr> {% endfor %} </tbody> </table></body></html>new_student.html(添加学生的表单)
Section titled “new_student.html(添加学生的表单)”<!DOCTYPE html><html><head> <title>Add New Student</title> <style> label { display: block; margin-bottom: 5px; } input[type=text], textarea { width: 300px; margin-bottom: 10px; } .alert-error { color: #721c24; background-color: #f8d7da; border-color: #f5c6cb; padding: 10px; margin-bottom: 10px; border-radius: 4px; } </style></head><body> <h1>添加学生信息</h1>
<!-- Display flashed messages (e.g., validation errors) --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category == 'error' %} <div class="alert alert-{{ category }}">{{ message }}</div> {% endif %} {% endfor %} {% endif %} {% endwith %}
<form method="post"> <label for="name">姓名:</label> <input type="text" name="name" id="name" required><br>
<label for="addr">地址:</label> <textarea name="addr" id="addr"></textarea><br>
<label for="city">城市:</label> <input type="text" name="city" id="city"><br>
<label for="pin">邮编:</label> <input type="text" name="pin" id="pin"><br>
<input type="submit" value="添加学生"> </form> <p><a href="{{ url_for('index') }}">返回列表</a></p></body></html>关键改进和注意事项:
Section titled “关键改进和注意事项:”- Python 3: 代码使用 Python 3 语法(例如,
print()函数)。 - 上下文管理(
with): 尽管在此简单的get_db_connection示例中未使用,但在更复杂的场景中,建议使用with sqlite3.connect(...) as conn:,因为它在许多情况下会自动处理 commits 和 rollbacks。在这里,我们在try...except...finally块中手动管理commit()和rollback(),以清晰地展示插入逻辑。 - 错误处理: 包含基本的
try...except块用于数据库错误,并将错误打印到标准错误输出。 sqlite3.Row: 用于按列名访问查询结果。- 闪现消息: 使用 Flask 的
flash()函数和模板中的get_flashed_messages()来提供用户反馈(需要设置app.config['SECRET_KEY'])。 - 重定向: 在表单提交后使用
redirect(url_for('index'))以获得更好的流程(Post/Redirect/Get 模式)。 - 基本验证: 包含一个简单的检查
if not name:。 - 安全: 请注意,此示例未实现健壮的输入验证或 sanitization(清理),这对于实际应用至关重要,以防止 SQL 注入和其他漏洞。
- 可扩展性: 直接使用
sqlite3对于简单情况是没问题的。对于更大或更复杂的应用,强烈建议使用对象关系映射(ORM),如 SQLAlchemy,通常通过Flask-SQLAlchemy扩展。它提供了更高级别的抽象,简化了数据库交互,并有助于更有效地管理数据库连接。这将在后续章节中介绍。
运行应用(python app.py)并访问 http://localhost:5000/。你可以查看列表,点击“添加新学生”,填写表单,提交,然后查看更新后的列表。