本文我们将构建一个增删改查的Todo应用,该web app基于Python3.7 开发,用到了Flask和SqlAlchemy两个三方库。Flask 是Python 的一个流行简单的web框架,SqlAlchemy 提供了更简洁的操作数据库方式。至于前端加入一些CSS 样式,以便美观。
准备环境
首先,我们使用pip来安装所需要的依赖,命令如下:
pip install Flask Flask-SQLAlchemy
然后在根目录创建一个template文件夹,Flask框架会自动识别该文件夹下的HTML文件,我们可以创建index.html 文件,现在目录结构如下:
接着,我们需要导入相关依赖。第一步我们需要初始化Flask 应用(我们传入当前模块名__name__ 作为参数),然后我们创建数据库连接,我使用的是基本文件数据库SQLite 。如果你有一个更复杂的数据库作为单独的进程(MariaDB 、Postgres )运行,只需要更改连接字符串。 然后我们将此字符串作为URI数据库地址传递并运行SQLAlchemy ,重要的是定义数据库模型。
import os
from datetime import datetime
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATABASE_FILE = "sqlite:///{}".format(os.path.join(BASE_DIR, "todo.db"))
app.config["SQLALCHEMY_DATABASE_URI"] = DATABASE_FILE
db = SQLAlchemy(app)
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
text = db.Column(db.Text)
done = db.Column(db.Boolean)
date = db.Column(db.DateTime, default=datetime.now())
为此,我们创建了Note表,带有自增id、todo任务的文本、标识是否保存的字段done和一个自动日期字段date。稍后我们将使用此模型初始化数据库。
增删改查
我们需要创建4个方法来做增删改查,实现Todo App的功能。
def create_todo(text):
todo = Todo(text=text)
db.session.add(todo)
db.session.commit()
db.session.refresh(todo)
def read_todos():
return db.session.query(Todo).all()
def update_todo(todo_id, text, done):
db.session.query(Todo).filter_by(id=todo_id).update({
"text": text,
"done": True if done == "on" else False
})
db.session.commit()
def delete_todo(todo_id):
db.session.query(Todo).filter_by(id=todo_id).delete()
db.session.commit()
create_note 方法只有文本作为参数。首先,我们创建一个新的Todo,将此参数作为文本传递并保存在数据库中。对于read_notes ,我们只列出数据库中的所有Todo记录。update_note 方法有2个参数,text和done。text是要更新的Todo的文本,done是我们将创建的表单的复选框的值。如果此复选框的值为“on”(即已选中),则存储的布尔值done将为True,否则为False。删除方法delete_note即从数据库中移除Todo记录即可。
主页
@app.route("/", methods=["POST", "GET"])
def index():
if request.method == "POST":
create_todo(request.form["text"])
return render_template("index.html", todos=read_todos())
在 Flask 框架中,路由是使用@app.route 装饰器定义的。第一个参数是URL,另一个可选参数包含允许的请求方法,在我们的例子中是用于表单处理的POST和GET。POST方法意味着我们正在发送一个带有新创建任务的表单。但是无论是POST还是GET,我们都会显示index.html 模板,并将我们存储在数据库中的所有任务(read_todos)传递给Jinja模板系统,将它们渲染到模板中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todo</title>
</head>
<body>
<h2>新建</h2>
<form method="post" action="/">
<label>
<input type="text" name="text" placeholder="新增一条Todo">
</label>
<button type="submit" value="update">新增</button>
</form>
<h2>列表</h2>
{% for todo in todos %}
<p>
<input type="text" title="{{ todo.date }}" value="{{ todo.text }}" name="text">
</p>
{% endfor %}
</body>
</html>
前端表单将“/”路由映射到后端主页。它只有一个文本输入字段和一个提交按钮。然后我们将在todos变量中遍历我们传递给模板的所有记录并将它们全部显示出来。稍后我们将为每条记录添加一个表单,这样就可以从前端编辑和删除单个记录。现在,页面看起来像这样。我们可以添加和显示,但不能编辑和删除。此时如果我们运行Flask 应用,可以在5000端口看见页面如下:
增加编辑功能
编辑和删除的方法稍微复杂一些。我们将路由的相对地址指定为/edit/todo_id,即我们将向 URL 传递一个参数,我们将其命名为note_id,我们将它传递给 edit_todo方法。如果输入请求是通过POST发出的,我们将表单数据传递给update_todo函数以修改任务。如果作为GET请求,那么我们删除给定的任务。 完成后,我们会将所有内容重定向到原始页面。
<h2>列表</h2>
{% for todo in todos %}
<form method="POST" action="/edit/{{ todo.id }}">
<input type="hidden" name="done" value="off">
<label>
<input type="checkbox" onclick="redirect('/edit/{{ todo.id }}')"
data-target="/edit/{{ todo.id }}">
</label>
<input type="text" title="{{ todo.dateAdded }}" value="{{ todo.text }}" name="text">
<button type="submit" value="update">更新</button>
</form>
{% endfor %}
在Python 代码中,我们调用db.create_all ,它使用我们指定的所有表(在我们的例子中,只有Todo )创建一个数据库,然后运行整个Flask 应用程序。
@app.route("/edit/<todo_id>", methods=["POST", "GET"])
def edit_todo(todo_id):
if request.method == "POST":
update_todo(todo_id, text=request.form['text'], done=request.form['done'])
elif request.method == "GET":
delete_todo(todo_id)
return redirect("/", code=302)
if __name__ == '__main__':
db.create_all()
app.run(debug=True)
到此为止,所有的功能都已经实现,最后,我们调整模板,使其看起来更加美观。这需要对现有HTML 代码进行CSS 修饰,这个过程不过多介绍。
让我们看看最终的效果:
源码
以上所有源代码已经上传至GitHub
|