如何在 Flask 和 SQLite 中使用 Python-Markdown

作者选择了 COVID-19 救援基金作为 Write for Donations计划的一部分接受捐款。

介绍

Flask是使用 Python 语言构建 Web 应用程序的框架,使用 Flask,您可以使用 SQLite作为您的数据库引擎来存储应用程序数据。

Markdown是一个标记语言,通常用于在易于阅读的文本格式中写内容的过程。使用Markdown,您可以用标题,链接和图像等功能格式化简单文本,然后可以将文本转换为HTML,其中包括这些格式化功能。

Python-Markdown是一个Python库,允许您将Markdown文本转换为HTML;它大多遵循Markdown标准,与标准Markdown语法有少数差异(https://python-markdown.github.io/#differences)。

在本教程中,您将使用Flask,SQLite和Python-Markdown来构建一个小型备注的Web应用程序,该应用程序将允许用户显示,创建和格式化标题,链接,列表,图像和其他功能。

前提条件

步骤一:建立依赖性

在此步骤中,您将激活您的 Python 环境并使用 pip 包安装程序安装 Flask 和 Python-Markdown. 然后您将创建您将使用的数据库来存储笔记并添加一些样本数据。

首先,如果您尚未启用您的编程环境:

1source env/bin/activate

一旦激活了编程环境,请使用以下命令安装Flask和Python-Markdown库:

1pip install flask markdown

然后创建一个名为schema.sql的数据库架构文件,其中包含 SQL 命令来创建一个笔记表。

1nano schema.sql

在此文件中输入以下 SQL 命令:

1[label flask_notes/schema.sql]
2DROP TABLE IF EXISTS notes;
3
4CREATE TABLE notes (
5    id INTEGER PRIMARY KEY AUTOINCREMENT,
6    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
7    content TEXT NOT NULL
8);

在此 SQL 文件中,您首先删除任何已存在的表名为笔记,这可能会导致问题。这确保您的笔记表完全如本 SQL 中所述。

您可以使用「CREATE TABLE NOTES」语句来创建包含以下列的「Notes」表:

  • id:代表一个 primary key 的整数;数据库将为每个输入(注释)分配一个独特的值。
  • created: 注释的创建日期;它将自动填写注释被添加到数据库的时间。

保存并关闭文件。

若要使用schema.sql文件创建数据库,请在flask_notes目录中打开名为init_db.py的文件:

1nano init_db.py

然后添加以下代码:

 1[label flask_notes/init_db.py]
 2
 3import sqlite3
 4
 5connection = sqlite3.connect('database.db')
 6
 7with open('schema.sql') as f:
 8    connection.executescript(f.read())
 9
10cur = connection.cursor()
11
12cur.execute("INSERT INTO notes (content) VALUES (?)", ('# The First Note',))
13cur.execute("INSERT INTO notes (content) VALUES (?)", ('_Another note_',))
14cur.execute("INSERT INTO notes (content) VALUES (?)", ('Visit [this page](https://andsky.com/tech/tutorials) for more tutorials.',))
15
16connection.commit()
17connection.close()

在这里,您首先导入sqlite3模块,然后连接到一个名为database.db的文件,该文件将在运行该程序后创建。database.db是存储所有应用程序数据的数据库,然后打开schema.sql文件并使用executescript()(https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection.executescript)方法运行它,同时执行多个SQL陈述。

使用 Cursor 对象,您执行几个INSERT SQL 语句来创建三个笔记. 您在这里使用 Markdown 语法:第一个笔记是<h1>标题,第二个笔记是意大利语,第三个笔记包含链接. 您在 execute()方法中使用`?

最后,您执行更改并关闭连接。

保存并关闭文件。

运行这个程序:

1python init_db.py

執行後,一個名為「database.db」的新檔案會出現在您的「flask_notes」目錄中。

您已激活您的环境,安装了 Flask 和 Python-Markdown,并创建了 SQLite 数据库。接下来,您将从数据库中获取 Markdown 笔记,将其转换为 HTML,并在应用程序的主页上显示。

步骤 2 – 在索引页面上显示笔记

在此步骤中,您将创建一个Flask应用程序,连接到数据库并显示您在数据库中所拥有的样本数据,然后将数据库中的Markdown文本转换为HTML,然后在索引页面上渲染。

首先,在您的flask_notes目录中创建app.py应用程序文件:

1nano app.py

添加以下代码:

1[label flask_notes/app.py]
2import sqlite3
3import markdown
4from flask import Flask, render_template, request, flash, redirect, url_for
5
6def get_db_connection():
7    conn = sqlite3.connect('database.db')
8    conn.row_factory = sqlite3.Row
9    return conn

您首先导入sqlite3模块、标记包和Flask 助手。

「get_db_connection()」函数打开了连接到「database.db」数据库文件,然后将 row_factory属性设置为「sqlite3.Row」。 这为您提供了基于名称的访问列,这意味着数据库连接会返回行为像常规Python字典的行。

接下来,添加下一个代码片段:

1[label flask_notes/app.py]
2#. . .
3
4app = Flask(__name__)
5app.config['SECRET_KEY'] = 'this should be a secret random string'

在这里,您创建了 Flask 应用程序对象,并将秘密密密钥设置为 安全会话

然后添加以下代码:

 1[label flask_notes/app.py]
 2#. . .
 3
 4@app.route('/')
 5def index():
 6    conn = get_db_connection()
 7    db_notes = conn.execute('SELECT id, created, content FROM notes;').fetchall()
 8    conn.close()
 9
10    notes = []
11    for note in db_notes:
12       note = dict(note)
13       note['content'] = markdown.markdown(note['content'])
14       notes.append(note)
15
16    return render_template('index.html', notes=notes)

index() 函数是 Flask view function,这是使用特殊 @app.route decorator装饰的函数。

index()视图函数中,您打开数据库连接并执行一个SELECT SQL 语句,以获取notes表的所有行ID、创建日期和内容。

要将笔记内容从 Markdown 转换为 HTML,你会创建一个名为notes的新空列表。你会穿过db_notes列表并将每个笔记从sqlite3.Row转换为常规的 Python 字典,使用dict() Python 函数来允许分配。接下来,你会使用markdown.markdown()函数将note['content]的值转换为 HTML。例如,调用markdown.markdown('#Hi')会返回字符串<h1>Hi</h1>,因为在markdown#代表<h1>标题。修改note['content]后,你会将笔记附加到notes列表中。

最后,您会渲染一个名为index.html的模板文件,将其传递到注释列表中。

在所有添加后,您的文件将如下:

 1[label flask_notes/app.py]
 2import sqlite3
 3import markdown
 4from flask import Flask, render_template, request, flash, redirect, url_for
 5
 6def get_db_connection():
 7    conn = sqlite3.connect('database.db')
 8    conn.row_factory = sqlite3.Row
 9    return conn
10
11app = Flask(__name__)
12app.config['SECRET_KEY'] = 'this should be a secret random string'
13
14@app.route('/')
15def index():
16    conn = get_db_connection()
17    db_notes = conn.execute('SELECT id, created, content FROM notes;').fetchall()
18    conn.close()
19
20    notes = []
21    for note in db_notes:
22       note = dict(note)
23       note['content'] = markdown.markdown(note['content'])
24       notes.append(note)
25
26    return render_template('index.html', notes=notes)

保存并关闭文件。

接下来,您将创建一个基础模板和index.html模板文件。

在您的flask_notes目录中,创建一个模板目录,并在其内部打开一个名为base.html的文件:

1mkdir templates
2nano templates/base.html

如果你不熟悉Flask中的HTML模板,请阅读How To Make A Web Application Using Flask in Python 3(LINK1):

 1[label flask_notes/templates/base.html]
 2<!doctype html>
 3<html lang="en">
 4  <head>
 5    <!-- Required meta tags -->
 6    <meta charset="utf-8">
 7    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 8
 9    <!-- Bootstrap CSS -->
10    <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">
11
12    <title>{% block title %} {% endblock %}</title>
13  </head>
14  <body>
15    <nav class="navbar navbar-expand-md navbar-light bg-light">
16        <a class="navbar-brand" href="{{ url_for('index')}}">FlaskNotes</a>
17        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
18            <span class="navbar-toggler-icon"></span>
19        </button>
20        <div class="collapse navbar-collapse" id="navbarNav">
21            <ul class="navbar-nav">
22            <li class="nav-item active">
23                <a class="nav-link" href="#">About</a>
24            </li>
25            </ul>
26        </div>
27    </nav>
28    <div class="container">
29        {% for message in get_flashed_messages() %}
30            <div class="alert alert-danger">{{ message }}</div>
31        {% endfor %}
32        {% block content %} {% endblock %}
33    </div>
34
35    <!-- Optional JavaScript -->
36    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
37    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
38    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
39    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
40  </body>
41</html>

上一块的大部分代码是标准的HTML和Bootstrap所需的代码. 网页浏览器的<meta>标签提供信息, Bootstrap CSS 文件的<link>标签链接,而<script>标签是 JavaScript 代码的链接,允许一些额外的 Bootstrap 功能。

标签 <title>{% block title %} {% endblock %}</title> 允许继承模板定义自定义标题. 您可以使用 for message in get_flashed_messages() 循环显示闪存消息,如警告和警告。

保存并关闭文件。

接下来,创建将这个base.html文件扩展的index.html文件:

1nano templates/index.html

添加以下代码:

 1[label flask_notes/templates/index.html]
 2
 3{% extends 'base.html' %}
 4
 5{% block content %}
 6    <h1>{% block title %} Welcome to FlaskNotes {% endblock %}</h1>
 7    {% for note in notes %}
 8    <div class="card">
 9        <div class="card-body">
10            <span class="badge badge-primary">#{{ note['id'] }}</span>
11            <span class="badge badge-default">{{ note['created'] }}</span>
12            <hr>
13            <p>{{ note['content'] |safe }}</p>
14        </div>
15    </div>
16    <hr>
17    {% endfor %}
18{% endblock %}

在这里,您扩展 base.html,定义一个标题,并使用一个 for 循环来浏览在 Bootstrap 卡中显示每个笔记的笔记,您显示笔记的 ID,笔记的创建日期和笔记的内容,您在 index() 视图中将其转换为 HTML。

您使用的 gcsafe Jinja 过滤器,您将其应用到使用 gcsafe的内容上;这类似于在 Python 中调用一个函数(类似于call(note(content))))。 callsafe 过滤器允许浏览器渲染 HTML 代码,如果没有应用,它会将 HTML 显示为纯文本。这通常被称为escaping HTML,这是一个防止恶意 HTML 在浏览器中被解释的安全特性,这会导致一个危险的安全漏洞,称为 cross-site scripting (XSS)。 由于 Python-Markdown 库返回了安全的 HTML,您可以允许浏览器使用callsafe 过滤器渲染它。 请记

有关更多信息,请阅读 Flask 关于 [控制自动逃避] 的文档(https://flask.palletsprojects.com/en/1.1.x/templating/#controlling-autoescaping)。

保存并关闭文件。

设置环境变量 Flask 需求,然后使用以下命令运行应用程序:

1export FLASK_APP=app
2export FLASK_ENV=development
3flask run

FLASK_APP环境变量指定你要运行的应用程序(app.py文件)。 FLASK_ENV环境变量指定模式;development意味着应用程序将在开发模式下运行,调试器运行(请记住避免在生产中使用这种模式)。

打开浏览器并输入URL http://127.0.0.1:5000/

Flask Notes Index

在这里,你会发现每个笔记在浏览器中被格式化和渲染为HTML,而不是简单的文本。

您创建了一个Flask应用程序,连接到数据库,收集笔记,将其内容从Markdown文本转换为HTML,然后在索引页面上渲染它们。

步骤 3 – 添加新笔记

在此步骤中,您将添加一个新的路径,允许用户创建新笔记. 用户可以使用 Markdown 语法来编写他们的笔记 — 您的应用程序将将笔记保存到数据库中,然后在索引页面上显示以适当的格式化。

您将使用网页表格允许用户在您的 Flask 应用程序中提交数据,并将用户提交的数据存储在您的数据库中。

首先打开app.py文件以添加新的路线:

1nano app.py

将下列代码添加到文件的末尾:

 1[label flask_notes/app.py]
 2#. . .
 3
 4@app.route('/create/', methods=('GET', 'POST'))
 5def create():
 6    conn = get_db_connection()
 7
 8    if request.method == 'POST':
 9        content = request.form['content']
10        if not content:
11            flash('Content is required!')
12            return redirect(url_for('index'))
13        conn.execute('INSERT INTO notes (content) VALUES (?)', (content,))
14        conn.commit()
15        conn.close()
16        return redirect(url_for('index'))
17
18    return render_template('create.html')

由于您将使用此路线通过 Web 表单将新数据插入到数据库中,因此您可以使用 app.route() 装饰器中的 `methods=('GET', 'POST') 来允许 GET 和 POST 请求。

如果用户提交了一种表单,这意味着条件 request.method == 'POST' 是正确的,那么您会提取用户使用 request.form['content'] 提交的笔记内容,并将其保存到名为 content' 的变量中。如果内容是空的,则会闪烁一个 'Content is required!' 消息,并将用户重定向到索引页面。

如果请求是 GET 请求,这意味着用户刚刚访问了该页面,您会渲染一个名为 'create.html' 的模板文件。

保存并关闭文件。

接下来,打开create.html模板文件:

1nano templates/create.html

添加以下代码:

 1[label flask_notes/templates/create.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <h1>{% block title %} Add a New Note {% endblock %}</h1>
 6    <form method="post">
 7    <div class="form-group">
 8        <label for="content">Note Content</label>
 9        <textarea type="text" name="content"
10               placeholder="Note content, you can use Markdown syntax" class="form-control"
11               value="{{ request.form['content'] }}" autofocus></textarea>
12    </div>
13
14    <div class="form-group">
15        <button type="submit" class="btn btn-primary">Submit</button>
16    </div>
17    </form>
18
19{% endblock %}

在这里,您使用具有文本区域的表单来记录笔记的内容. 您使用request.form访问存储的表单数据,以便在您的表单提交中发生错误的情况下(例如,如果没有提供内容)。

保存并关闭文件。

接下来打开base.html文件,将新笔记按钮添加到导航栏中:

1nano templates/base.html

用突出的代码编辑文件如下:

 1[label flask_notes/templates/base.html]
 2<!doctype html>
 3<html lang="en">
 4  <head>
 5    <!-- Required meta tags -->
 6    <meta charset="utf-8">
 7    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 8
 9    <!-- Bootstrap CSS -->
10    <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">
11
12    <title>{% block title %} {% endblock %}</title>
13  </head>
14  <body>
15    <nav class="navbar navbar-expand-md navbar-light bg-light">
16        <a class="navbar-brand" href="{{ url_for('index')}}">FlaskNotes</a>
17        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
18            <span class="navbar-toggler-icon"></span>
19        </button>
20        <div class="collapse navbar-collapse" id="navbarNav">
21            <ul class="navbar-nav">
22            <li class="nav-item active">
23                <a class="nav-link" href="#">About</a>
24            </li>
25
26            <li class="nav-item active">
27                <a class="nav-link" href="{{ url_for('create') }}">New Note</a>
28           </li>
29            </ul>
30        </div>
31    </nav>
32    <div class="container">
33        {% for message in get_flashed_messages() %}
34            <div class="alert alert-danger">{{ message }}</div>
35        {% endfor %}
36        {% block content %} {% endblock %}
37    </div>
38
39    <!-- Optional JavaScript -->
40    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
41    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
42    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
43    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
44  </body>
45</html>

您可以使用url_for()函数将新的<li>项添加到导航栏中,以链接到create()视图函数。

运行开发服务器,如果您还没有:

1flask run

使用您的浏览器前往http://127.0.0.1:5000/create并添加以下标记:

1### Flask
2Flask is a **web** framework for _Python_.
3
4Here is the Flask logo:
5
6![Flask Logo](https://cdn.jsdelivr.net/gh/andsky/tutorials-images/others/d2ae434912527efde5a0b28e55be9777_flask-logo.png)

这个标记包含一个h3标题,大胆的web字,意大利语的Python字和图像。

提交笔记,你会发现你的应用程序将其格式化为HTML。

Markdown Formatted Note

您现在有一个新的路径,允许用户将新笔记添加到数据库中. 用户可以使用 Markdown 格式进行笔记,应用程序将在索引页面上显示 HTML 中的笔记。

您可以从 此存储库获取该应用程序的完整代码。

结论

您创建了一个 Flask 应用程序以在 Markdown 格式中创建笔记,以允许用户使用文本格式,如标题、大胆和语文本、添加图像和链接等。您将应用程序连接到 SQLite 数据库以存储和检索数据。您已将 Markdown 文本嵌入到 HTML 转换中,以便笔记在页面上进行渲染。 有关在 Python 中使用 Markdown 的更多信息,请参阅 How To Use Python-Markdown to Convert Markdown Text to HTML

有关Flask的更多信息,请查看以下教程:

使用 Flask 和 SQLite 使用 One-to-Many Database Relationships 如何使用(https://andsky.com/tech/tutorials/how-to-use-one-to-many-database-relationships-with-flask-and-sqlite)。

Published At
Categories with 技术
Tagged with
comments powered by Disqus