如何在Flask和SQLite中使用Python-Markdown
作者选择了 COVID-19 Relief Fund 作为 Write for DOnations 计划的一部分来接受捐赠。
介绍
Flask 是一个使用 Python 语言 构建 Web 应用程序的框架。 使用 Flask,您可以使用 SQLite 作为数据库引擎来存储应用程序数据。
Markdown 是一种标记语言,通常用于以易于阅读的文本格式编写内容的过程。 使用 Markdown,您可以使用标题、链接和图像等功能格式化纯文本,然后可以将文本转换为包含这些格式化功能的 HTML。 要了解如何使用 Markdown,请查看 Markdown 语法 标准。
Python-Markdown 是一个 Python 库,可让您将 Markdown 文本转换为 HTML; 它主要遵循 Markdown 标准,与标准 Markdown 语法 有一些小的 差异。
在本教程中,您将使用 Flask、SQLite 和 Python-Markdown 构建一个支持使用 Markdown 格式化文本的小型笔记 Web 应用程序。 该应用程序将允许用户显示、创建和格式化带有标题、链接、列表、图像和其他功能的笔记。 您将使用 Bootstrap 工具包来设置应用程序的样式。
先决条件
- 本地 Python 3 编程环境。 按照 如何为 Python 3 系列安装和设置本地编程环境中的分发教程进行操作。 本教程将项目目录命名为
flask_notes
。 - 了解基本的 Flask 概念,例如创建路由、呈现 HTML 模板和连接到 SQLite 数据库。 如果您不熟悉这些概念,请查看 如何在 Python 3 中使用 Flask 制作 Web 应用程序和 如何在 Python 3 中使用 sqlite3 模块。
第 1 步 — 设置依赖项
在此步骤中,您将激活 Python 环境并使用 pip 包安装程序安装 Flask 和 Python-Markdown。 然后,您将创建用于存储笔记的数据库并向其中添加一些示例数据。
首先,如果您还没有激活您的编程环境:
source env/bin/activate
激活编程环境后,使用以下命令安装 Flask 和 Python-Markdown 库:
pip install flask markdown
然后创建一个名为 schema.sql
的数据库模式文件,其中将包含用于创建 notes
表的 SQL 命令。 打开 flask_notes
目录中的文件:
nano schema.sql
在此文件中键入以下 SQL 命令:
flask_notes/schema.sql
DROP TABLE IF EXISTS notes; CREATE TABLE notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, content TEXT NOT NULL );
在此 SQL 文件中,您首先删除任何已存在的名为 notes
的表,这可能会导致问题。 这可确保您的 notes
表与此 SQL 中的描述完全相同。 请注意,无论何时使用这些 SQL 命令,这都会删除数据库中的所有内容,因此请确保在完成本教程并试验最终结果之前不要在 Web 应用程序中编写任何重要内容。
您使用 CREATE TABLE notes
语句创建具有以下列的 notes
表:
id
:一个整数,代表一个主键; 数据库将为每个条目(注释)分配一个唯一值。created
:笔记的创建日期; 它将自动填写注释添加到数据库的时间。content
:笔记的内容。
保存并关闭文件。
要使用 schema.sql
文件创建数据库,请在 flask_notes
目录中打开一个名为 init_db.py
的文件:
nano init_db.py
然后添加以下代码:
烧瓶笔记/init_db.py
import sqlite3 connection = sqlite3.connect('database.db') with open('schema.sql') as f: connection.executescript(f.read()) cur = connection.cursor() cur.execute("INSERT INTO notes (content) VALUES (?)", ('# The First Note',)) cur.execute("INSERT INTO notes (content) VALUES (?)", ('_Another note_',)) cur.execute("INSERT INTO notes (content) VALUES (?)", ('Visit [this page](https://www.digitalocean.com/community/tutorials) for more tutorials.',)) connection.commit() connection.close()
在这里,您首先导入 sqlite3
模块。 接下来,您连接到一个名为 database.db
的文件,该文件将在您执行此程序后创建。 database.db
是将保存所有应用程序数据的数据库。 然后,您打开 schema.sql
文件并使用同时执行多个 SQL 语句的 executescript() 方法运行它。 这将创建 notes
表。
使用 Cursor 对象,您可以执行几个 INSERT
SQL 语句来创建三个注释。 您在这里使用 Markdown 语法:第一个注释是 <h1>
标题,第二个注释是斜体,第三个注释包含一个链接。 您在 execute() 方法中使用 ?
占位符并传递一个包含便笺内容的元组以安全地将数据插入数据库。
最后,您提交更改并关闭连接。
保存并关闭文件。
运行程序:
python init_db.py
执行后,一个名为 database.db
的新文件将出现在您的 flask_notes
目录中。
你已经激活了你的环境,安装了 Flask 和 Python-Markdown,并创建了 SQLite 数据库。 接下来,您将从数据库中检索 Markdown 注释,将它们转换为 HTML,并将它们显示在应用程序的主页上。
第 2 步 — 在索引页面上显示注释
在此步骤中,您将创建一个 Flask 应用程序,该应用程序连接到数据库并显示您在数据库中的示例数据。 您将数据库中的 Markdown 文本转换为 HTML,然后将其呈现在索引页面上。
首先,在 flask_notes
目录中创建 app.py
应用程序文件:
nano app.py
向其中添加以下代码:
烧瓶笔记/app.py
import sqlite3 import markdown from flask import Flask, render_template, request, flash, redirect, url_for def get_db_connection(): conn = sqlite3.connect('database.db') conn.row_factory = sqlite3.Row return conn
您首先导入 sqlite3
模块、markdown
包和 Flask 助手。
get_db_connection()
函数打开到 database.db
数据库文件的连接,然后将 row_factory 属性设置为 sqlite3.Row
。 这使您可以基于名称访问列,这意味着数据库连接将返回行为类似于常规 Python 字典的行。 最后,该函数返回您将用于访问数据库的 conn
连接对象。
之后,添加下一段代码:
烧瓶笔记/app.py
#. . . app = Flask(__name__) app.config['SECRET_KEY'] = 'this should be a secret random string'
在这里,您创建 Flask 应用程序对象并将密钥设置为 安全会话 。
然后添加以下代码:
烧瓶笔记/app.py
#. . . @app.route('/') def index(): conn = get_db_connection() db_notes = conn.execute('SELECT id, created, content FROM notes;').fetchall() conn.close() notes = [] for note in db_notes: note = dict(note) note['content'] = markdown.markdown(note['content']) notes.append(note) return render_template('index.html', notes=notes)
index()
函数是一个 Flask view 函数,它是一个使用特殊的 @app.route
decorator 修饰的函数。 Flask 将此函数的返回值转换为 HTTP 客户端(例如 Web 浏览器)将显示的 HTTP 响应。
在 index()
视图函数中,打开数据库连接并执行 SELECT
SQL 语句来获取 [X181X 的所有行的 ID、创建日期和内容] 桌子。 您使用 fetchall()
方法获取所有行的列表并将此数据保存在 db_notes
变量中。 然后,您关闭连接。
要将注释的内容从 Markdown 转换为 HTML,您需要创建一个名为 notes
的新空列表。 您遍历 db_notes
列表并使用 dict()
Python 函数将每个音符从 sqlite3.Row
转换为常规 Python 字典以允许分配。 接下来,您使用 markdown.markdown()
函数将 note['content']
的值转换为 HTML。 例如,调用 markdown.markdown('#Hi')
将返回字符串 '<h1>Hi</h1>'
,因为在 Markdown 中 #
表示 <h1>
标题。 修改 note['content']
后,将注释附加到 notes
列表中。
最后,渲染一个名为 index.html
的模板文件,并将 notes
列表传递给它。
添加完所有内容后,您的文件将如下所示:
烧瓶笔记/app.py
import sqlite3 import markdown from flask import Flask, render_template, request, flash, redirect, url_for def get_db_connection(): conn = sqlite3.connect('database.db') conn.row_factory = sqlite3.Row return conn app = Flask(__name__) app.config['SECRET_KEY'] = 'this should be a secret random string' @app.route('/') def index(): conn = get_db_connection() db_notes = conn.execute('SELECT id, created, content FROM notes;').fetchall() conn.close() notes = [] for note in db_notes: note = dict(note) note['content'] = markdown.markdown(note['content']) notes.append(note) return render_template('index.html', notes=notes)
保存并关闭文件。
接下来,您将创建一个基本模板和 index.html
模板文件。
在您的 flask_notes
目录中,创建一个 templates
目录并在其中打开一个名为 base.html
的文件:
mkdir templates nano templates/base.html
在 base.html
中添加以下代码; 请注意,您在这里使用 Bootstrap 。 如果您不熟悉 Flask 中的 HTML 模板,请阅读 如何在 Python 3 中使用 Flask 制作 Web 应用程序的第 3 步:
flask_notes/templates/base.html
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <title>{% block title %} {% endblock %}</title> </head> <body> <nav class="navbar navbar-expand-md navbar-light bg-light"> <a class="navbar-brand" href="{{ url_for('index')}}">FlaskNotes</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" href="#">About</a> </li> </ul> </div> </nav> <div class="container"> {% for message in get_flashed_messages() %} <div class="alert alert-danger">{{ message }}</div> {% endfor %} {% block content %} {% endblock %} </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </body> </html>
前面代码块中的大部分代码是标准 HTML 和 Bootstrap 所需的代码。 <meta>
标签为 Web 浏览器提供信息,<link>
标签链接 Bootstrap CSS 文件,而 <script>
标签是 JavaScript 代码的链接,允许一些额外的 Bootstrap 功能。
<title>{% block title %} {% endblock %}</title>
标签允许继承模板定义自定义标题。 您使用 for message in get_flashed_messages()
循环来显示闪烁的消息,例如警告和警报。 {% block content %} {% endblock %}
占位符是继承模板放置内容的位置,以便所有模板都具有此基本模板提供的额外代码以避免重复。
保存并关闭文件。
接下来,创建将扩展此 base.html
文件的 index.html
文件:
nano templates/index.html
向其中添加以下代码:
flask_notes/templates/index.html
{% extends 'base.html' %} {% block content %} <h1>{% block title %} Welcome to FlaskNotes {% endblock %}</h1> {% for note in notes %} <div class="card"> <div class="card-body"> <span class="badge badge-primary">#{{ note['id'] }}</span> <span class="badge badge-default">{{ note['created'] }}</span> <hr> <p>{{ note['content'] |safe }}</p> </div> </div> <hr> {% endfor %} {% endblock %}
在这里,您扩展 base.html
,定义标题,并使用 for
循环遍历显示 引导卡 中的每个注释的注释。 您可以在 index()
视图函数中显示便笺的 ID、便笺的创建日期和便笺的内容,这些内容已转换为 HTML。
您使用 |safe
Jinja 过滤器,您使用 |
将其应用于内容; 这类似于在 Python 中调用函数(类似于 safe(note['content'])
)。 |safe
过滤器允许浏览器呈现 HTML 代码——如果没有应用,它会将 HTML 显示为纯文本。 这通常被称为“转义 HTML”,这是一种安全功能,可防止恶意 HTML 在浏览器中被解释,从而导致称为 跨站点脚本 (XSS) 的危险安全漏洞。 由于 Python-Markdown 库返回安全的 HTML,您可以允许浏览器使用 |safe
过滤器来呈现它。 请记住,在您确定您允许的 HTML 代码是安全且受信任的之前,不要使用此过滤器。
有关更多信息,请阅读 Flask 关于 控制自动转义 的文档。
保存并关闭文件。
设置 Flask 需要的环境变量并使用以下命令运行应用程序:
export FLASK_APP=app export FLASK_ENV=development flask run
FLASK_APP
环境变量指定您要运行的应用程序(app.py
文件)。 FLASK_ENV
环境变量指定模式; development
表示应用程序将在调试器运行的情况下以开发模式运行(请记住避免在生产中使用此模式)。 使用 flask run
命令运行应用程序。
打开浏览器并输入 URL http://127.0.0.1:5000/
。
在这里,您会发现每条笔记都被格式化并在浏览器中呈现为 HTML 而不是纯文本。
您创建了一个 Flask 应用程序,它连接到数据库、获取笔记、将其内容从 Markdown 文本转换为 HTML,然后在索引页面上呈现它们。 接下来,您将添加一个路由以允许用户添加新注释,他们可以使用 Markdown 语法编写这些注释。
第 3 步 — 添加新注释
在此步骤中,您将添加一条允许用户记新笔记的新路线。 用户可以使用 Markdown 语法来编写他们的笔记——您的应用程序会将笔记保存到数据库中,然后它将以正确的格式显示在索引页面上。 您还将向导航栏添加一个按钮,将用户带到这个新页面。
您将使用 Web 表单来允许用户在 Flask 应用程序中提交数据,并将用户提交的数据存储在数据库中。
首先打开app.py
文件添加新路由:
nano app.py
将以下代码添加到文件末尾:
烧瓶笔记/app.py
#. . . @app.route('/create/', methods=('GET', 'POST')) def create(): conn = get_db_connection() if request.method == 'POST': content = request.form['content'] if not content: flash('Content is required!') return redirect(url_for('index')) conn.execute('INSERT INTO notes (content) VALUES (?)', (content,)) conn.commit() conn.close() return redirect(url_for('index')) return render_template('create.html')
由于您将使用此路由通过 Web 表单将新数据插入数据库,因此您在 app.route()
装饰器中允许使用 methods=('GET', 'POST')
的 GET 和 POST 请求。 在 create()
视图函数中,您打开一个数据库连接。
如果用户提交的表单意味着条件 request.method == 'POST'
为真,那么您使用 request.form['content']
提取用户提交的便笺内容并将其保存到名为 content
的变量中]。 如果内容为空,则闪烁 'Content is required!'
消息并将用户重定向到索引页面。 如果内容不为空,则使用 INSERT
SQL 语句将便笺的内容添加到 notes
表中。 您提交更改并关闭连接,然后将用户重定向到索引页面。
如果请求是 GET 请求,这意味着用户刚刚访问了该页面,则呈现一个名为 create.html
的模板文件。
保存并关闭文件。
接下来,打开create.html
模板文件:
nano templates/create.html
向其中添加以下代码:
flask_notes/templates/create.html
{% extends 'base.html' %} {% block content %} <h1>{% block title %} Add a New Note {% endblock %}</h1> <form method="post"> <div class="form-group"> <label for="content">Note Content</label> <textarea type="text" name="content" placeholder="Note content, you can use Markdown syntax" class="form-control" value="{{ request.form['content'] }}" autofocus></textarea> </div> <div class="form-group"> <button type="submit" class="btn btn-primary">Submit</button> </div> </form> {% endblock %}
在这里,您使用带有文本区域的表单来存储笔记的内容。 您使用 request.form
访问存储的表单数据,以防您的表单提交出现问题(例如,如果没有提供内容)。 您在文本区域下添加一个提交按钮,供用户按下以在 POST 请求中将数据发送到应用程序。
保存并关闭文件。
接下来打开 base.html
文件,在导航栏中添加一个 New Note
按钮:
nano templates/base.html
使用突出显示的代码编辑文件,如下所示:
flask_notes/templates/base.html
<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <!-- Bootstrap CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <title>{% block title %} {% endblock %}</title> </head> <body> <nav class="navbar navbar-expand-md navbar-light bg-light"> <a class="navbar-brand" href="{{ url_for('index')}}">FlaskNotes</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" href="#">About</a> </li> <li class="nav-item active"> <a class="nav-link" href="{{ url_for('create') }}">New Note</a> </li> </ul> </div> </nav> <div class="container"> {% for message in get_flashed_messages() %} <div class="alert alert-danger">{{ message }}</div> {% endfor %} {% block content %} {% endblock %} </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script> </body> </html>
您使用 url_for()
函数将新的 <li>
项目添加到导航栏以链接到 create()
视图函数。 有了这个,您可以从导航栏访问用于创建新笔记的页面。
如果您还没有运行开发服务器:
flask run
使用浏览器转到 http://127.0.0.1:5000/create
并添加以下降价注释:
### Flask Flask is a **web** framework for _Python_. Here is the Flask logo: ![Flask Logo](https://flask.palletsprojects.com/en/1.1.x/_images/flask-logo.png)
此降价包含一个 h3
标题、粗体字 web
、斜体字 Python
和图像。
提交注释,您会发现您的应用程序将其格式化为 HTML。
您现在有了一个允许用户向数据库添加新注释的新路径。 用户可以使用 Markdown 格式做笔记,应用程序将在索引页面上以 HTML 格式显示笔记。
您可以从 这个存储库 访问应用程序的完整代码。
结论
您创建了一个 Flask 应用程序,用于以 Markdown 格式记笔记,以允许用户使用文本格式,例如标题、粗体和斜体文本、添加图像和链接等。 您将应用程序连接到 SQLite 数据库以存储和检索数据。 您已将 Markdown 文本合并到 HTML 转换中,以便注释将呈现在页面上。 要了解有关在 Python 中使用 Markdown 的更多信息,请阅读 如何使用 Python-Markdown 将 Markdown 文本转换为 HTML 。
有关 Flask 的更多信息,请查看以下教程: