如何在 Flask 应用程序中使用 PostgreSQL 数据库

作者选择了 自由和开源基金作为 写给捐款计划的一部分接受捐款。

介绍

在网络应用程序中,你通常需要一个数据库,这是一个有组织的数据收集。你使用数据库来存储和维护可有效地检索和操纵的持久数据。例如,在社交媒体应用程序中,你有一个数据库,其中用户数据(个人信息,帖子,评论,追随者)是以一种可以有效地操纵的方式存储的。你可以将数据添加到数据库,检索它,修改它或删除它,取决于不同的要求和条件。在网络应用程序中,这些要求可能是用户添加新帖子,删除帖子,或删除他们的帐户,这可能或可能不会删除他们的帖子。你执行的操作来操纵数据将取决于应用程序中的特定功能。例如,你可能不想让用户添加没有标题的帖子。

Flask 是一个轻量级的 Python 网页框架,提供用于在 Python 语言中创建网页应用程序的有用的工具和功能。 PostgreSQL,或 Postgres,是一个关系式数据库管理系统,提供了 SQL查询语言的实现。

在本教程中,您将构建一个小型书籍评论网络应用程序,展示如何使用 psycopg2库,一个PostgreSQL数据库适配器,允许您在Python中与您的PostgreSQL数据库进行交互。

前提条件

在本教程中,项目目录被称为flask_app

步骤 1 – 创建 PostgreSQL 数据库和用户

在此步骤中,您将创建一个名为flask_db的数据库和一个名为sammy的数据库用户。

在 Postgres 安装过程中,创建了一个名为 postgres 的操作系统用户,以匹配 postgres 的 PostgreSQL 管理用户. 您需要使用这个用户来执行管理任务。

使用以下命令登录一个互动的 Postgres 会话:

1sudo -iu postgres psql

您将收到一个PostgreSQL提示,您可以设置您的要求。

首先,为您的项目创建一个数据库:

1CREATE DATABASE flask_db;

<$>[注] **注:**每个 Postgres 语句都必须以半列结束,因此,如果您遇到问题,请确保您的命令以一个结束。

接下来,为我们的项目创建一个数据库用户. 请确保选择安全密码:

1CREATE USER sammy WITH PASSWORD 'password';

然后给这个新用户访问权限来管理你的新数据库:

1GRANT ALL PRIVILEGES ON DATABASE flask_db TO sammy;

若要确认创建数据库,请通过键入以下命令获取数据库列表:

1\l

您将在数据库列表中看到flask_db

完成后,通过键入退出 PostgreSQL 提示:

1\q

Postgres 现在已设置,以便您可以通过 Python 连接和管理其数据库信息,使用psycopg2库。

步骤 2 — 安装 Flask 和 psycopg2

在此步骤中,您将安装Flask和psycopg2库,以便您可以使用Python与您的数据库进行交互。

当您的虚拟环境启用时,使用pip来安装Flask和psycopg2库:

1pip install Flask psycopg2-binary

一旦安装成功完成,您将在输出结束时看到一个类似于以下的行:

1[secondary_label Output]
2
3Successfully installed Flask-2.0.2 Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.2 click-8.0.3 itsdangerous-2.0.1 psycopg2-binary-2.9.2

您现在已经在虚拟环境中安装了所需的包,接下来,您将连接并设置您的数据库。

步骤三:创建数据库

在此步骤中,您将在您的flask_app项目目录中创建一个Python文件,以连接到flask_db数据库,创建一个存储书籍的表,并将一些书籍与评论插入其中。

首先,在激活您的编程环境时,请在您的flask_app目录中打开名为init_db.py的新文件。

1nano init_db.py

此文件将打开连接到flask_db数据库,创建一个名为books的表,并使用样本数据填充表格。

 1[label flask_app/init_db.py]
 2import os
 3import psycopg2
 4
 5conn = psycopg2.connect(
 6        host="localhost",
 7        database="flask_db",
 8        user=os.environ['DB_USERNAME'],
 9        password=os.environ['DB_PASSWORD'])
10
11# Open a cursor to perform database operations
12cur = conn.cursor()
13
14# Execute a command: this creates a new table
15cur.execute('DROP TABLE IF EXISTS books;')
16cur.execute('CREATE TABLE books (id serial PRIMARY KEY,'
17                                 'title varchar (150) NOT NULL,'
18                                 'author varchar (50) NOT NULL,'
19                                 'pages_num integer NOT NULL,'
20                                 'review text,'
21                                 'date_added date DEFAULT CURRENT_TIMESTAMP);'
22                                 )
23
24# Insert data into the table
25
26cur.execute('INSERT INTO books (title, author, pages_num, review)'
27            'VALUES (%s, %s, %s, %s)',
28            ('A Tale of Two Cities',
29             'Charles Dickens',
30             489,
31             'A great classic!')
32            )
33
34cur.execute('INSERT INTO books (title, author, pages_num, review)'
35            'VALUES (%s, %s, %s, %s)',
36            ('Anna Karenina',
37             'Leo Tolstoy',
38             864,
39             'Another great classic!')
40            )
41
42conn.commit()
43
44cur.close()
45conn.close()

保存并关闭文件。

在此文件中,您首先导入将用于访问环境变量的 os模块,您将存储您的数据库用户名和密码,以便它们在源代码中不可见。

您导入了psycopg2库,然后使用psycopg2.connect()函数打开了连接到flask_db数据库,您指定了主机,在这种情况下是 localhost。

您通过os.environ对象提供您的用户名和密码,这使您可以访问您在编程环境中设置的环境变量。您将数据库用户名存储在名为DB_USERNAME的环境变量中,以及密码存储在名为DB_PASSWORD的环境变量中。

您使用 connection.cursor() 方法创建一个名为 cur 的方针,该方法允许 Python 代码在数据库会话中执行 PostgreSQL 命令。

如果它已经存在的话,你会使用 cursor 的 execute() 方法删除 books 表,这将避免另一个名为 books 的表存在的可能性,这可能会导致混淆的行为(例如,如果它有不同的列)。这里不是这样的情况,因为你还没有创建表,所以SQL 命令不会执行。 请注意,当你执行这个 init_db.py 文件时,这将删除所有现有的数据。 为了我们的目的,你只会执行此文件一次来启动数据库,但你可能想再次执行它以删除你输入的任何数据并重新开始最初的样本数据。

然后使用创建表格书籍创建一个名为书籍的表格,其中包含以下列:

  • 联合国 id': " 序列 " 类型的标识,即自动递增整数。 此列代表 _ 主要密钥_ 您使用 PRIMARY 关键词指定 。 数据库将为每个条目指定此密钥的独特值( _) ) * 标题: 书名"varchar"类型,是可变长度有限度的字符类型.varchar (150)'是指标题可长达150个字符。 " NOT NULL " 表示此列不能为空。 (_) ) *作者': 该书的作者,限制为50个人物. " NOT NULL " 表示此列不能为空。 (_) ) * 页-num: 代表书页数的整数。 " NOT NULL " 表示此列不能为空。 (_) ( )* " 审查 " : 书评. " 文本 " 类型表示审查可以是任何长度的文本。 (_) ( )* 日期-加': 该书的日期被添加到表上. Default'将一栏的默认值设置为CURRENT_TIMESTAMP',这是该书被添加到数据库的时间。 和 id 一样, 您不需要为此列指定一个值, 因为它会自动填入 。 ( _) (英语)

创建表后,您使用指示器的执行()方法将两本书插入表中,查尔斯·迪肯斯的两个城市的故事和托尔斯泰的安娜·卡列尼娜

一旦您完成将书籍数据插入表中,您将使用 connection.commit() 方法进行交易并将更改应用到数据库中。

要建立数据库连接,请通过运行以下命令设置DB_USERNAMEDB_PASSWORD环境变量。

1export DB_USERNAME="sammy"
2export DB_PASSWORD="password"

现在,使用python命令在终端中运行您的init_db.py文件:

1python init_db.py

一旦该文件在没有错误的情况下完成执行,将添加一个新的书籍表到您的flask_db数据库中。

登录一个互动的 Postgres 会话,查看新的书籍表。

1sudo -iu postgres psql

使用\c命令连接到flask_db数据库:

1\c flask_db

然后使用SELECT语句从书籍表中获取书籍的标题和作者:

1SELECT title, author FROM books;

您将看到如下这样的输出:

1title         |      author
2----------------------+------------------
3 A Tale of Two Cities | Charles Dickens
4 Anna Karenina        | Leo Tolstoy

\q结束交互式会话。

接下来,您将创建一个小型的 Flask 应用程序,连接到数据库,获取您插入数据库的两本书评论,并在索引页面上显示它们。

步骤 4 - 显示书籍

在此步骤中,您将创建一个Flask应用程序,具有索引页面,可以检索数据库中的书籍,并显示它们。

当您的编程环境启用并安装Flask时,请打开名为app.py的文件,在您的flask_app目录中进行编辑:

1nano app.py

此文件将设置您的数据库连接,并创建一个单一的 Flask 路径来使用该连接。

 1[label flask_app/app.py]
 2import os
 3import psycopg2
 4from flask import Flask, render_template
 5
 6app = Flask(__name__)
 7
 8def get_db_connection():
 9    conn = psycopg2.connect(host='localhost',
10                            database='flask_db',
11                            user=os.environ['DB_USERNAME'],
12                            password=os.environ['DB_PASSWORD'])
13    return conn
14
15@app.route('/')
16def index():
17    conn = get_db_connection()
18    cur = conn.cursor()
19    cur.execute('SELECT * FROM books;')
20    books = cur.fetchall()
21    cur.close()
22    conn.close()
23    return render_template('index.html', books=books)

保存并关闭文件。

在这里,您从flask包中导入os模块、psycopg2库以及Flask类和render_template()

您定义了一个名为get_db_connection()的函数,该函数使用您在DB_USERNAMEDB_PASSWORD环境变量中存储的用户和密码来打开与flask_db数据库的连接。

index()视图中,你使用get_db_connection()函数打开一个数据库连接,创建一个路由器,并执行SELECT * FROM图书,以获取数据库中的所有图书。你使用fetchall()方法将数据保存到名为books的变量中。然后你关闭了路由器和连接。最后,你返回了render_template()函数的呼叫,以返回名为index.html的模板文件,将它传递到你从数据库中获取的图书列表到books变量中。

要在索引页面上显示您在数据库中所拥有的书籍,您首先将创建一个基础模板,该模板将具有其他模板也将使用的所有基本HTML代码,以避免代码重复。

创建一个模板目录,然后打开一个名为base.html的新模板:

1mkdir templates
2nano templates/base.html

将以下代码添加到base.html文件中:

 1[label flask_app/templates/base.html]
 2<!DOCTYPE html>
 3<html lang="en">
 4<head>
 5    <meta charset="UTF-8">
 6    <title>{% block title %} {% endblock %}- FlaskApp</title>
 7    <style>
 8        nav a {
 9            color: #d64161;
10            font-size: 3em;
11            margin-left: 50px;
12            text-decoration: none;
13        }
14
15        .book {
16            padding: 20px;
17            margin: 10px;
18            background-color: #f7f4f4;
19        }
20
21        .review {
22                margin-left: 50px;
23                font-size: 20px;
24        }
25
26    </style>
27</head>
28<body>
29    <nav>
30        <a href="{{ url_for('index') }}">FlaskApp</a>
31        <a href="#">About</a>
32    </nav>
33    <hr>
34    <div class="content">
35        {% block content %} {% endblock %}
36    </div>
37</body>
38</html>

保存并关闭文件。

此基础模板包含您在其他模板中需要重复使用的所有HTML锅炉板。标题块将被更换为为每个页面设置一个标题,而内容块将被替换为每个页面的内容。导航栏有两个链接,一个用于索引页面,其中您使用url_for()辅助函数链接到index()视图函数,另一个用于关于**页面,如果您选择在应用程序中包含一个。

接下来,打开一个名为index.html的模板,这是你在app.py文件中提到的模板:

1nano templates/index.html

添加以下代码:

 1[label flask_app/templates/index.html]
 2
 3{% extends 'base.html' %}
 4
 5{% block content %}
 6    <h1>{% block title %} Books {% endblock %}</h1>
 7    {% for book in books %}
 8        <div class='book'>
 9            <h3>#{{ book[0] }} - {{ book[1] }} BY {{ book[2] }}</h3>
10            <i><p>({{ book[3] }} pages)</p></i>
11            <p class='review'>{{ book[4] }}</p>
12            <i><p>Added {{ book[5] }}</p></i>
13        </div>
14    {% endfor %}
15{% endblock %}

保存并关闭文件。

在此文件中,您扩展了基础模板,并取代了内容块的内容,您使用一个<h1>标题,它也作为标题。

您在字段中使用 Jinja for loop 来浏览书籍列表中的每个书籍,您会显示书籍ID,这是使用书籍[0]的第一个项目。

在您的flask_app目录中启用虚拟环境时,请使用FLASK_APP环境变量告诉Flask关于该应用程序(在这种情况下是app.py) 然后将FLASK_ENV环境变量设置为development,以便在开发模式下运行应用程序并获取调试器的访问。有关Flask调试器的更多信息,请参阅如何处理Flask应用程序中的错误(LINK0)。

1export FLASK_APP=app
2export FLASK_ENV=development

请确保您已设置DB_USERNAMEDB_PASSWORD环境变量,如果您还没有:

1export DB_USERNAME="sammy"
2export DB_PASSWORD="password"

接下来,运行应用程序:

1flask run

当开发服务器运行时,请使用您的浏览器访问以下URL:

1http://127.0.0.1:5000/

您将看到您在第一个启动时添加到数据库的书籍。

Index Page

您已经在索引页面上显示了数据库中的书籍,您现在需要允许用户添加新书籍,您将在下一步添加新路线来添加书籍。

步骤五:添加新书

在此步骤中,您将创建一个新路径,以将新书籍和评论添加到数据库中。

您将添加一个包含网页表单的页面,用户会输入书籍标题、书籍作者、页数和书籍评论。

让开发服务器运行,并打开一个新的终端窗口。

首先,打开app.py文件:

1nano app.py

要处理网页表格,您需要从包中导入几件东西:

  • 全球 request对象访问提交的数据
  • url_for()函数生成 URL
  • redirect()函数将用户重定向到索引页面后添加一本书到数据库

将这些导入添加到文件中的第一行:

1[label flask_app/app.py]
2
3from flask import Flask, render_template, request, url_for, redirect
4
5# ...

然后在app.py文件的末尾添加以下路线:

1[label flask_app/app.py]
2
3# ...
4
5@app.route('/create/', methods=('GET', 'POST'))
6def create():
7    return render_template('create.html')

保存并关闭文件。

在此路径中,您将‘GET’,‘POST’字符串传输到‘methods’参数,以允许 GET 和 POST 请求。 GET 请求用于从服务器中获取数据。 POST 请求用于将数据发送到特定路径。默认情况下,仅允许 GET 请求。当用户使用 GET 请求首次请求‘/create’ 路径时,将生成一个名为 ‘create.html’ 的模板文件。之后,您将编辑此路径来处理用户填写和提交 Web 表格以添加新书籍的 POST 请求。

打开新的create.html模板:

1nano templates/create.html

添加以下代码:

 1[label flask_app/templates/create.html]
 2{% extends 'base.html' %}
 3
 4{% block content %}
 5    <h1>{% block title %} Add a New Book {% endblock %}</h1>
 6    <form method="post">
 7        <p>
 8            <label for="title">Title</label>
 9            <input type="text" name="title"
10                   placeholder="Book title">
11            </input>
12        </p>
13
14        <p>
15            <label for="author">Author</label>
16            <input type="text" name="author"
17                   placeholder="Book author">
18            </input>
19        </p>
20
21        <p>
22            <label for="pages_num">Number of pages</label>
23            <input type="number" name="pages_num"
24                   placeholder="Number of pages">
25            </input>
26        </p>
27        <p>
28        <label for="review">Review</label>
29        <br>
30        <textarea name="review"
31                  placeholder="Review"
32                  rows="15"
33                  cols="60"
34                  ></textarea>
35        </p>
36        <p>
37            <button type="submit">Submit</button>
38        </p>
39    </form>
40{% endblock %}

保存并关闭文件。

您可以扩展基础模板,将标题设置为标题,并使用<form>标签,属性方法设置为发布,以表示表单将提交 POST 请求。

您有一个名为标题的文本字段,您将使用它来访问您的/Create路径中的标题数据。

你有一个文本字段为作者,一个数字字段为页数,和一个文本区域为书评。

最后,您在表单的末尾有一个提交按钮。

现在,随着开发服务器运行,使用您的浏览器导航到‘/create’路径:

1http://127.0.0.1:5000/create

您将看到一个 ** 添加新书 ** 页面,其中有一个输入字段为书的标题,一个为其作者,一个为书的页数,一个文本区域为书的评论,一个 ** 提交 ** 按钮。

Add a New Book

如果您填写表单并提交它,将 POST 请求发送到服务器,则不会发生任何事情,因为您没有在/create路径上处理 POST 请求。

打开 app.py 来处理用户提交的 POST 请求:

1nano app.py

编辑/create路径以显示如下:

 1[label flask_app/app.py]
 2
 3# ...
 4
 5@app.route('/create/', methods=('GET', 'POST'))
 6def create():
 7    if request.method == 'POST':
 8        title = request.form['title']
 9        author = request.form['author']
10        pages_num = int(request.form['pages_num'])
11        review = request.form['review']
12
13        conn = get_db_connection()
14        cur = conn.cursor()
15        cur.execute('INSERT INTO books (title, author, pages_num, review)'
16                    'VALUES (%s, %s, %s, %s)',
17                    (title, author, pages_num, review))
18        conn.commit()
19        cur.close()
20        conn.close()
21        return redirect(url_for('index'))
22
23    return render_template('create.html')

保存并关闭文件。

您在if request.method ==POST条件内处理 POST 请求,您从request.form`对象中提取标题、作者、页数和用户提交的评论。

您使用get_db_connection()函数打开数据库,然后创建一个指针,然后执行一个INSERT INTO SQL 语句,插入标题、作者、页数,并审查向书籍表提交的用户。

您发起交易并关闭 cursor 和连接。

最后,您将用户重定向到索引页面,在那里他们可以看到现有书籍下面新添加的书籍。

当开发服务器运行时,使用您的浏览器导航到‘/create’路径:

1http://127.0.0.1:5000/create

用一些数据填写表格并提交它。

您将被重定向到索引页面,在那里您将看到您的新书评论。

接下来,您将在导航栏中添加到创建页面的链接。

1nano templates/base.html

编辑文件以显示如下:

 1[label flask_app/templates/base.html]
 2
 3<!DOCTYPE html>
 4<html lang="en">
 5<head>
 6    <meta charset="UTF-8">
 7    <title>{% block title %} {% endblock %} - FlaskApp</title>
 8    <style>
 9        nav a {
10            color: #d64161;
11            font-size: 3em;
12            margin-left: 50px;
13            text-decoration: none;
14        }
15
16        .book {
17            padding: 20px;
18            margin: 10px;
19            background-color: #f7f4f4;
20        }
21
22        .review {
23                margin-left: 50px;
24                font-size: 20px;
25        }
26
27    </style>
28</head>
29<body>
30    <nav>
31        <a href="{{ url_for('index') }}">FlaskApp</a>
32        <a href="{{ url_for('create') }}">Create</a>
33        <a href="#">About</a>
34    </nav>
35    <hr>
36    <div class="content">
37        {% block content %} {% endblock %}
38    </div>
39</body>
40</html>

保存并关闭文件。

在这里,您将新的<a>链接添加到指向创建页面的导航栏。

更新您的索引页面,您将在导航栏中看到新的链接。

您现在有一个网页表格,用于添加新书评论. 有关网页表格的更多信息,请参阅 如何在 Flask 应用程序中使用网页表格. 有关管理网页表格的更先进和更安全的方法,请参阅 如何使用和验证使用 Flask-WTF 的网页表格

结论

您已经构建了一个与PostgreSQL数据库通信的书评小型Web应用程序,您在Flask应用程序中具有基本的数据库功能,例如将新数据添加到数据库中,检索数据并在页面上显示数据。

如果您想了解更多关于Flask的信息,请参阅Flask系列中的其他教程(https://www.digitalocean.com/community/tutorial_series/how-to-create-web-sites-with-flask)。

Published At
Categories with 技术
comments powered by Disqus