Как использовать базу данных PostgreSQL в приложении Flask

Автор выбрал Фонд свободного и открытого исходного кода для получения пожертвования в рамках программы Написать ради пожертвований.

Введение

В веб-приложениях обычно требуется база данных, которая представляет собой организованную коллекцию данных. Вы используете базу данных для хранения и поддержки постоянных данных, которые могут быть эффективно извлечены и обработаны. Например, в приложении социальных медиа у вас есть база данных, где хранятся данные пользователей (личная информация, сообщения, комментарии, подписчики) таким образом, чтобы их можно было эффективно обрабатывать. Вы можете добавлять данные в базу данных, извлекать их, изменять или удалять в зависимости от различных требований и условий. В веб-приложении эти требования могут заключаться в том, чтобы пользователь добавил новый пост, удалил пост или свой аккаунт, который может или не может удалить свои посты. Действия, которые вы выполняете для манипулирования данными, будут зависеть от конкретных функций вашего приложения. Например, вы можете не хотеть, чтобы пользователи добавляли сообщения без заголовков.

Фласк – это легкий веб-фреймворк на языке Python, который предоставляет полезные инструменты и функции для создания веб-приложений на языке Python. PostgreSQL, или Postgres, – это система управления реляционными базами данных, которая предоставляет реализацию языка запросов SQL. Он соответствует стандартам и имеет множество расширенных функций, таких как надежные транзакции и параллелизм без блокировки чтения.

В этом учебнике вы создадите небольшое веб-приложение для обзора книг, которое демонстрирует, как использовать библиотеку psycopg2, адаптер базы данных PostgreSQL, который позволяет вам взаимодействовать с базой данных PostgreSQL на языке Python. Вы будете использовать его с Flask для выполнения основных задач, таких как подключение к серверу баз данных, создание таблиц, вставка данных в таблицу и извлечение данных из таблицы.

Предварительные требования

Шаг 1 — Создание базы данных и пользователя PostgreSQL

На этом этапе вы создадите базу данных с именем flask_db и пользователя базы данных с именем sammy для вашего приложения Flask.

Во время установки Postgres был создан пользователь операционной системы с именем postgres, соответствующий административному пользователю PostgreSQL postgres. Вам нужно использовать этого пользователя для выполнения административных задач. Вы можете использовать sudo и передать имя пользователя с опцией -iu.

Войдите в интерактивную сессию Postgres, используя следующую команду:

  1. sudo -iu postgres psql

Вы получите приглашение командной строки PostgreSQL, где сможете настроить свои требования.

Сначала создайте базу данных для вашего проекта:

  1. CREATE DATABASE flask_db;

Примечание: Каждый оператор Postgres должен заканчиваться точкой с запятой, поэтому убедитесь, что ваша команда завершается одной, если у вас возникают проблемы.

Затем создайте пользователя базы данных для нашего проекта. Убедитесь, что выбираете безопасный пароль:

  1. CREATE USER sammy WITH PASSWORD 'password';

Затем предоставьте этому новому пользователю доступ к администрированию вашей новой базы данных:

  1. GRANT ALL PRIVILEGES ON DATABASE flask_db TO sammy;

Чтобы подтвердить создание базы данных, получите список баз данных, набрав следующую команду:

  1. \l

Вы увидите flask_db в списке баз данных.

Когда закончите, выйдите из приглашения PostgreSQL, набрав:

  1. \q

Теперь Postgres настроен так, что вы можете подключаться к нему и управлять его базовой информацией с помощью Python с использованием библиотеки psycopg2. Далее вы установите эту библиотеку наряду с пакетом Flask.

Шаг 2 — Установка Flask и psycopg2

На этом этапе вы установите Flask и библиотеку psycopg2, чтобы взаимодействовать с вашей базой данных с помощью Python.

С активированной виртуальной средой используйте pip, чтобы установить Flask и библиотеку psycopg2:

  1. pip install Flask psycopg2-binary

После успешного завершения установки вы увидите строку, аналогичную следующей, в конце вывода:

Output
Successfully 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

Теперь у вас установлены необходимые пакеты в вашей виртуальной среде. Далее вы подключитесь и настроите вашу базу данных.

Шаг 3 — Настройка базы данных

На этом этапе вы создадите файл Python в каталоге вашего проекта flask_app для подключения к базе данных flask_db, создания таблицы для хранения книг и вставки некоторых книг с отзывами в нее.

Сначала, активируйте ваше программное окружение и откройте новый файл с именем init_db.py в каталоге вашего flask_app.

  1. nano init_db.py

Этот файл откроет соединение с базой данных flask_db, создаст таблицу с именем books и заполнит таблицу с использованием образцовых данных. Добавьте в него следующий код:

flask_app/init_db.py
import os
import psycopg2

conn = psycopg2.connect(
        host="localhost",
        database="flask_db",
        user=os.environ['DB_USERNAME'],
        password=os.environ['DB_PASSWORD'])

# Открываем курсор для выполнения операций с базой данных
cur = conn.cursor()

# Выполняем команду: это создает новую таблицу
cur.execute('DROP TABLE IF EXISTS books;')
cur.execute('CREATE TABLE books (id serial PRIMARY KEY,'
                                 'title varchar (150) NOT NULL,'
                                 'author varchar (50) NOT NULL,'
                                 'pages_num integer NOT NULL,'
                                 'review text,'
                                 'date_added date DEFAULT CURRENT_TIMESTAMP);'
                                 )

# Вставляем данные в таблицу

cur.execute('INSERT INTO books (title, author, pages_num, review)'
            'VALUES (%s, %s, %s, %s)',
            ('A Tale of Two Cities',
             'Charles Dickens',
             489,
             'A great classic!')
            )


cur.execute('INSERT INTO books (title, author, pages_num, review)'
            'VALUES (%s, %s, %s, %s)',
            ('Anna Karenina',
             'Leo Tolstoy',
             864,
             'Another great classic!')
            )

conn.commit()

cur.close()
conn.close()

Сохраните и закройте файл.

В этом файле вы сначала импортируете модуль os, который вы будете использовать для доступа к переменным среды, где вы будете хранить имя пользователя и пароль для вашей базы данных, чтобы они не были видны в вашем исходном коде.

Вы импортируете библиотеку psycopg2. Затем вы открываете соединение с базой данных flask_db, используя функцию psycopg2.connect(). Вы указываете хост, который в данном случае является локальным. Вы передаете имя базы данных параметру database.

Вы предоставляете свое имя пользователя и пароль через объект os.environ, который дает вам доступ к переменным среды, установленным в вашей среде программирования. Вы будете хранить имя пользователя базы данных в переменной среды с именем DB_USERNAME, а пароль – в переменной среды с именем DB_PASSWORD. Это позволяет вам хранить свое имя пользователя и пароль за пределами исходного кода, чтобы ваша чувствительная информация не утекала при сохранении исходного кода в системе контроля версий или загрузке на сервер в интернете. Даже если злоумышленник получит доступ к вашему исходному коду, он не получит доступ к базе данных.

Вы создаете курсор с именем cur, используя метод connection.cursor(), который позволяет выполнять команды PostgreSQL на языке Python в сеансе базы данных.

Вы используете метод execute() курсора для удаления таблицы books, если она уже существует. Это избегает возможности существования другой таблицы с именем books, что может привести к неоднозначному поведению (например, если у нее другие столбцы). Это не относится к данному случаю, потому что вы еще не создали таблицу, поэтому SQL-команда не будет выполнена. Обратите внимание, что это удалит все существующие данные при каждом выполнении этого файла init_db.py. Для наших целей вы выполните этот файл только один раз для инициализации базы данных, но вам может потребоваться выполнить его снова, чтобы удалить вставленные данные и начать снова с исходных образцов данных.

Затем вы используете CREATE TABLE books для создания таблицы с именем books со следующими столбцами:

  • id: Идентификатор типа serial, который является автоинкрементируемым целым числом. Этот столбец представляет собой первичный ключ, который вы указываете с помощью ключевых слов PRIMARY KEY. База данных назначит уникальное значение для этого ключа для каждой записи.
  • title: Название книги типа varchar, который является типом символов переменной длины с ограничением. varchar (150) означает, что название может быть длиной до 150 символов. NOT NULL означает, что этот столбец не может быть пустым.
  • author: Автор книги, с ограничением в 50 символов. NOT NULL означает, что этот столбец не может быть пустым.
  • pages_num: Целое число, представляющее количество страниц в книге. NOT NULL означает, что этот столбец не может быть пустым.
  • обзор: Обзор книги. Тип текст означает, что обзор может быть текстом любой длины.
  • дата_добавления: Дата добавления книги в таблицу. DEFAULT устанавливает значение по умолчанию для столбца как CURRENT_TIMESTAMP, что является временем добавления книги в базу данных. Так же как и id, вам не нужно указывать значение для этого столбца, так как оно будет автоматически заполнено.

После создания таблицы вы используете метод execute() курсора для вставки двух книг в таблицу, Повесть о двух городах Чарльза Диккенса и Анна Каренина Льва Толстого. Вы используете заполнитель %s для передачи значений в SQL-запрос. psycopg2 обрабатывает вставку в фоновом режиме таким образом, чтобы предотвратить атаки SQL-инъекций.

После завершения вставки данных о книгах в вашу таблицу вы используете метод connection.commit() для фиксации транзакции и применения изменений к базе данных. Затем вы убираете ненужные вещи, закрывая курсор с помощью cur.close() и соединение с помощью conn.close().

Для установления соединения с базой данных установите переменные среды DB_USERNAME и DB_PASSWORD, выполнив следующие команды. Помните использовать свое собственное имя пользователя и пароль:

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

Теперь выполните ваш файл init_db.py в терминале, используя команду python:

  1. python init_db.py

После завершения выполнения файла без ошибок в вашу базу данных flask_db будет добавлена новая таблица books.

Войдите в интерактивную сессию Postgres, чтобы проверить новую таблицу books.

  1. sudo -iu postgres psql

Подключитесь к базе данных flask_db с помощью команды \c:

  1. \c flask_db

Затем используйте оператор SELECT, чтобы получить заголовки и авторов книг из таблицы books:

  1. SELECT title, author FROM books;

Вы увидите вывод, подобный следующему:

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

Выйдите из интерактивной сессии с помощью \q.

Затем вы создадите небольшое приложение Flask, подключитесь к базе данных, извлечете два отзыва о книгах, которые вы добавили в базу данных, и отобразите их на главной странице.

Шаг 4 — Отображение книг

На этом этапе вы создадите приложение Flask с главной страницей, которая извлекает книги из базы данных и отображает их.

При активированной среде программирования и установленном Flask откройте файл с именем app.py для редактирования в вашем каталоге flask_app:

  1. nano app.py

Этот файл настроит подключение к вашей базе данных и создаст один маршрут Flask для использования этого соединения. Добавьте следующий код в файл:

flask_app/app.py
import os
import psycopg2
from flask import Flask, render_template

app = Flask(__name__)

def get_db_connection():
    conn = psycopg2.connect(host='localhost',
                            database='flask_db',
                            user=os.environ['DB_USERNAME'],
                            password=os.environ['DB_PASSWORD'])
    return conn


@app.route('/')
def index():
    conn = get_db_connection()
    cur = conn.cursor()
    cur.execute('SELECT * FROM books;')
    books = cur.fetchall()
    cur.close()
    conn.close()
    return render_template('index.html', books=books)

Сохраните и закройте файл.

Здесь вы импортируете модуль os, библиотеку psycopg2 и класс Flask и функцию render_template() из пакета flask. Вы создаете экземпляр приложения Flask с именем app.

Вы определяете функцию с именем get_db_connection(), которая открывает соединение с базой данных flask_db, используя имя пользователя и пароль, которые вы храните в переменных среды DB_USERNAME и DB_PASSWORD. Функция возвращает объект соединения conn, который вы будете использовать для доступа к базе данных.

Затем вы создаете основной маршрут / и функцию представления index(), используя декоратор app.route(). В функции представления index() вы открываете соединение с базой данных, используя функцию get_db_connection(), создаете курсор и выполняете SQL-запрос SELECT * FROM books; для получения всех книг, которые есть в базе данных. Вы используете метод fetchall() для сохранения данных в переменной с именем books. Затем вы закрываете курсор и соединение. Наконец, вы возвращаете вызов функции render_template() для отображения файла шаблона с именем index.html, передавая ему список книг, которые вы извлекли из базы данных в переменной books.

Для отображения книг, имеющихся в вашей базе данных, на главной странице сначала создайте базовый шаблон, который будет содержать всю основную HTML-разметку, которую будут использовать и другие шаблоны, чтобы избежать повторения кода. Затем создайте файл шаблона index.html, который вы вызываете в вашей функции index(). Чтобы узнать больше о шаблонах, см. Как использовать шаблоны в приложении Flask.

Создайте каталог templates, затем откройте новый шаблон с именем base.html:

  1. mkdir templates
  2. nano templates/base.html

Добавьте следующий код внутрь файла base.html:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %}- FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .book {
            padding: 20px;
            margin: 10px;
            background-color: #f7f4f4;
        }

        .review {
                margin-left: 50px;
                font-size: 20px;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Сохраните и закройте файл.

Этот базовый шаблон содержит всю необходимую заготовку HTML, которую вы будете использовать повторно в других шаблонах. Блок title будет заменен для установки заголовка на каждой странице, а блок content будет заменен содержимым каждой страницы. В навигационной панели две ссылки: одна для главной страницы, где вы используете вспомогательную функцию url_for() для связи с функцией представления index(), и другая для страницы О нас, если вы решите включить ее в ваше приложение.

Затем откройте шаблон с именем index.html. Это шаблон, на который вы ссылаетесь в файле app.py:

  1. nano templates/index.html

Добавьте в него следующий код:

flask_app/templates/index.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Books {% endblock %}</h1>
    {% for book in books %}
        <div class='book'>
            <h3>#{{ book[0] }} - {{ book[1] }} BY {{ book[2] }}</h3>
            <i><p>({{ book[3] }} pages)</p></i>
            <p class='review'>{{ book[4] }}</p>
            <i><p>Added {{ book[5] }}</p></i>
        </div>
    {% endfor %}
{% endblock %}

Сохраните и закройте файл.

В этом файле вы расширяете базовый шаблон и заменяете содержимое блока content. Вы используете заголовок <h1>, который также служит в качестве заголовка.

Вы используете цикл Jinja for в строке {% for book in books %} для перебора каждой книги в списке books. Вы отображаете идентификатор книги, который является первым элементом, используя book[0]. Затем вы отображаете название книги, автора, количество страниц, обзор и дату добавления книги.

Находясь в каталоге flask_app с активированным виртуальным окружением, сообщите Flask о приложении (app.py в данном случае), используя переменную среды FLASK_APP. Затем установите переменную среды FLASK_ENV в development, чтобы запустить приложение в режиме разработки и получить доступ к отладчику. Для получения дополнительной информации о отладчике Flask см. Как обрабатывать ошибки в приложении Flask. Используйте следующие команды:

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

Убедитесь, что установлены переменные среды DB_USERNAME и DB_PASSWORD, если они еще не установлены:

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

Затем запустите приложение:

  1. flask run

При работе сервера разработки посетите следующий URL в вашем браузере:

http://127.0.0.1:5000/

Вы увидите добавленные вами книги в базе данных при первой инициализации.

Вы отобразили книги в вашей базе данных на главной странице. Теперь вам нужно позволить пользователям добавлять новые книги. Вы добавите новый маршрут для добавления книг на следующем этапе.

Шаг 5 — Добавление новых книг

На этом этапе вы создадите новый маршрут для добавления новых книг и отзывов в базу данных.

Вы добавите страницу с веб-формой, где пользователи вводят название книги, автора книги, количество страниц и обзор книги.

Оставьте сервер разработки работающим и откройте новое окно терминала.

Сначала откройте файл app.py:

  1. nano app.py

Для обработки веб-формы вам потребуется импортировать несколько вещей из пакета flask:

  • Глобальный объект request для доступа к отправленным данным.
  • Функция url_for() для генерации URL-адресов.
  • Функция redirect() для перенаправления пользователей на главную страницу после добавления книги в базу данных.

Добавьте эти импорты на первую строку в файле:

flask_app/app.py

from flask import Flask, render_template, request, url_for, redirect

# ...

Затем добавьте следующий маршрут в конце файла app.py:

flask_app/app.py

# ...


@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

Сохраните и закройте файл.

На этом маршруте вы передаете кортеж ('GET', 'POST') параметру methods, чтобы разрешить как GET, так и POST запросы. GET запросы используются для получения данных с сервера. POST запросы используются для отправки данных на определенный маршрут. По умолчанию разрешены только GET запросы. Когда пользователь впервые запрашивает маршрут /create с помощью GET запроса, будет отображен файл шаблона с именем create.html. Позже вы отредактируете этот маршрут, чтобы обрабатывать POST запросы, когда пользователи заполняют и отправляют веб-форму для добавления новых книг.

Откройте новый шаблон create.html:

  1. nano templates/create.html

Добавьте следующий код в него:

flask_app/templates/create.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Add a New Book {% endblock %}</h1>
    <form method="post">
        <p>
            <label for="title">Title</label>
            <input type="text" name="title"
                   placeholder="Book title">
            </input>
        </p>

        <p>
            <label for="author">Author</label>
            <input type="text" name="author"
                   placeholder="Book author">
            </input>
        </p>

        <p>
            <label for="pages_num">Number of pages</label>
            <input type="number" name="pages_num"
                   placeholder="Number of pages">
            </input>
        </p>
        <p>
        <label for="review">Review</label>
        <br>
        <textarea name="review"
                  placeholder="Review"
                  rows="15"
                  cols="60"
                  ></textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

Сохраните и закройте файл.

Вы расширяете базовый шаблон, устанавливаете заголовок в качестве названия, и используете тег <form> с атрибутом method, установленным в post, чтобы указать, что форма будет отправлять POST запрос.

У вас есть текстовое поле с именем title, которое вы будете использовать для доступа к данным заголовка в вашем маршруте /create.

У вас есть текстовое поле для автора, числовое поле для количества страниц и текстовая область для обзора книги.

Наконец, у вас есть кнопка Submit в конце формы.

Теперь, при запущенном сервере разработки, используйте ваш браузер для перехода по маршруту /create:

http://127.0.0.1:5000/create

Вы увидите страницу Добавить новую книгу с полем ввода для названия книги, одним для ее автора, и одним для количества страниц в книге, текстовой областью для обзора книги и кнопкой Submit.

Если вы заполните форму и отправите ее, отправив POST-запрос на сервер, ничего не произойдет, потому что вы не обработали POST-запросы на маршруте /create.

Откройте app.py, чтобы обработать POST-запрос, который отправляет пользователь:

  1. nano app.py

Измените маршрут /create, чтобы он выглядел следующим образом:

flask_app/app.py

# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        author = request.form['author']
        pages_num = int(request.form['pages_num'])
        review = request.form['review']

        conn = get_db_connection()
        cur = conn.cursor()
        cur.execute('INSERT INTO books (title, author, pages_num, review)'
                    'VALUES (%s, %s, %s, %s)',
                    (title, author, pages_num, review))
        conn.commit()
        cur.close()
        conn.close()
        return redirect(url_for('index'))

    return render_template('create.html')

Сохраните и закройте файл.

Вы обрабатываете POST-запросы внутри условия if request.method == 'POST'. Вы извлекаете заголовок, автора, количество страниц и отзыв, который пользователь отправляет, из объекта request.form.

Вы открываете базу данных, используя функцию get_db_connection(), и создаете курсор. Затем вы выполняете SQL-запрос INSERT INTO, чтобы вставить заголовок, автора, количество страниц и отзыв, отправленный пользователем, в таблицу books.

Вы фиксируете транзакцию, закрываете курсор и соединение.

Наконец, вы перенаправляете пользователя на страницу индекса, где он может увидеть новую добавленную книгу под существующими книгами.

С запущенным сервером разработки используйте браузер, чтобы перейти на маршрут /create:

http://127.0.0.1:5000/create

Заполните форму данными и отправьте ее.

Вы будете перенаправлены на страницу индекса, где увидите свой новый обзор книги.

Затем вы добавите ссылку на страницу Создать в панели навигации. Откройте base.html:

  1. nano templates/base.html

Измените файл следующим образом:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .book {
            padding: 20px;
            margin: 10px;
            background-color: #f7f4f4;
        }

        .review {
                margin-left: 50px;
                font-size: 20px;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Сохраните и закройте файл.

Здесь вы добавляете новую ссылку <a> в панели навигации, которая ведет на страницу Создать.

Обновите вашу главную страницу, и вы увидите новую ссылку в панели навигации.

Теперь у вас есть страница с веб-формой для добавления новых обзоров книг. Для получения дополнительной информации о веб-формах см. Как использовать веб-формы в приложении Flask. Для более продвинутого и безопасного метода управления веб-формами см. Как использовать и проверять веб-формы с Flask-WTF.

Вывод

Вы создали небольшое веб-приложение для обзоров книг, которое взаимодействует с базой данных PostgreSQL. У вас есть базовая функциональность базы данных в вашем приложении Flask, такая как добавление новых данных в базу данных, извлечение данных и их отображение на странице.

Если вы хотите узнать больше о Flask, ознакомьтесь с другими учебными пособиями в серии уроков по Flask.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-a-postgresql-database-in-a-flask-application