Как использовать Flask-SQLAlchemy для взаимодействия с базами данных в приложении Flask

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

Введение

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

Разверните ваши приложения Flask из GitHub, используя Платформу приложений DigitalOcean. Позвольте DigitalOcean заботиться о масштабировании вашего приложения.

Flask – это легкий веб-фреймворк Python, который предоставляет полезные инструменты и функции для создания веб-приложений на языке Python. SQLAlchemy – это инструментарий SQL, который обеспечивает эффективный и высокопроизводительный доступ к базам данных для реляционных баз данных. Он предоставляет способы взаимодействия с несколькими базами данных, такими как SQLite, MySQL и PostgreSQL. Он предоставляет доступ к SQL-функционалу базы данных. Он также предоставляет средство сопоставления объектов с реляционной моделью (ORM), которое позволяет выполнять запросы и обрабатывать данные с помощью простых объектов и методов Python. Flask-SQLAlchemy – это расширение Flask, которое упрощает использование SQLAlchemy с Flask, предоставляя вам инструменты и методы для взаимодействия с базой данных в ваших приложениях Flask через SQLAlchemy.

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

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

Шаг 1 — Установка Flask и Flask-SQLAlchemy

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

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

  1. pip install Flask Flask-SQLAlchemy

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

Output
Successfully installed Flask-2.0.3 Flask-SQLAlchemy-2.5.1 Jinja2-3.0.3 MarkupSafe-2.1.0 SQLAlchemy-1.4.31 Werkzeug-2.0.3 click-8.0.4 greenlet-1.1.2 itsdangerous-2.1.0

После установки необходимых пакетов Python следующим шагом будет настройка базы данных.

Шаг 2 — Настройка базы данных и модели

На этом этапе вы настроите соединение с базой данных и создадите модель базы данных SQLAlchemy, которая является классом Python, представляющим таблицу, хранящую ваши данные. Вы инициируете базу данных, создадите таблицу для студентов на основе объявленной вами модели и добавите несколько студентов в таблицу студентов.

Настройка соединения с базой данных

Откройте файл под названием app.py в вашем каталоге flask_app. Этот файл будет содержать код для настройки базы данных и ваших маршрутов Flask:

  1. nano app.py

Этот файл будет подключаться к базе данных SQLite под названием database.db и содержать класс под названием Student, который представляет таблицу студентов вашей базы данных для хранения информации о студентах, а также ваши маршруты Flask. Добавьте следующие инструкции import в начало app.py:

flask_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func

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

Из пакета flask вы импортируете необходимые помощники для вашего приложения: класс Flask для создания экземпляра приложения Flask, функцию render_template() для рендеринга шаблонов, объект request для обработки запросов, функцию url_for() для создания URL-адресов маршрутов и функцию redirect() для перенаправления пользователей. Для получения дополнительной информации о маршрутах и шаблонах см. Как использовать шаблоны в приложении Flask.

Затем вы импортируете класс SQLAlchemy из расширения Flask-SQLAlchemy, которое предоставляет доступ ко всем функциям и классам из SQLAlchemy, а также помощникам и функционалу, который интегрирует Flask с SQLAlchemy. Вы будете использовать его для создания объекта базы данных, который подключается к вашему приложению Flask, позволяя вам создавать и управлять таблицами с использованием классов, объектов и функций Python, не прибегая к использованию языка SQL.

Также вы импортируете помощник func из модуля sqlalchemy.sql для доступа к SQL-функциям. Вам это понадобится в вашей системе управления студентами для установки значения по умолчанию для даты и времени создания записи студента.

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

flask_app/app.py

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

Здесь вы создаете путь для вашего файла базы данных SQLite. Сначала вы определяете базовый каталог как текущий каталог. Вы используете функцию os.path.abspath() для получения абсолютного пути к каталогу текущего файла. Специальная переменная __file__ содержит путь к текущему файлу app.py. Вы сохраняете абсолютный путь базового каталога в переменной с именем basedir.

Затем вы создаете экземпляр приложения Flask с именем app, который вы используете для настройки двух ключей конфигурации Flask-SQLAlchemy конфигурационных ключей:

  • SQLALCHEMY_DATABASE_URI: URI базы данных для указания базы данных, с которой вы хотите установить соединение. В этом случае URI следует формату sqlite:///путь/к/базе/данных.db. Вы используете функцию os.path.join() для интеллектуального объединения базового каталога, который вы построили и сохранели в переменной basedir, и имени файла database.db. Это позволит подключиться к файлу базы данных database.db в вашем каталоге flask_app. Файл будет создан после инициации базы данных.

  • SQLALCHEMY_TRACK_MODIFICATIONS: Конфигурация для включения или отключения отслеживания модификаций объектов. Вы устанавливаете его в False, чтобы отключить отслеживание и использовать меньше памяти. Для получения дополнительной информации см. страницу конфигурации в документации Flask-SQLAlchemy.

Примечание:

Если вы хотите использовать другой движок базы данных, такой как PostgreSQL или MySQL, вам потребуется использовать соответствующий URI.

Для PostgreSQL используйте следующий формат:

postgresql://username:password@host:port/database_name

Для MySQL:

mysql://username:password@host:port/database_name

Для получения дополнительной информации см. документацию SQLAlchemy по конфигурации движка.

После настройки SQLAlchemy путем установки URI базы данных и отключения отслеживания вы создаете объект базы данных, используя класс SQLAlchemy, передавая экземпляр приложения для подключения вашего приложения Flask с SQLAlchemy. Вы сохраняете ваш объект базы данных в переменной с именем db. Вы будете использовать этот объект db для взаимодействия с вашей базой данных.

Объявление Таблицы

После установки соединения с базой данных и создания объекта базы данных вы будете использовать объект базы данных для создания таблицы базы данных для студентов, которая представлена моделью — классом Python, который наследуется от базового класса, предоставленного Flask-SQLAlchemy через экземпляр базы данных db, созданный ранее. Чтобы определить таблицу студентов как модель, добавьте следующий класс в ваш файл app.py:

flask_app/app.py
# ...

class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

Здесь вы создаете модель Student, которая наследуется от класса db.Model. Это представляет таблицу студентов. Вы используете класс db.Column для определения столбцов вашей таблицы. Первый аргумент представляет тип столбца, а дополнительные аргументы представляют конфигурацию столбца.

Вы определяете следующие столбцы для модели Student:

  • id: Идентификатор студента. Определяется как целое число с помощью db.Integer. primary_key=True определяет этот столбец как первичный ключ, который будет назначен уникальное значение базой данных для каждой записи (то есть для каждого студента).
  • firstname: Имя студента. Строка с максимальной длиной 100 символов. nullable=False указывает, что этот столбец не должен быть пустым.
  • lastname: Фамилия студента. Строка с максимальной длиной 100 символов. nullable=False указывает, что этот столбец не должен быть пустым.
  • email: Адрес электронной почты студента. Строка с максимальной длиной 80 символов. unique=True указывает, что каждый адрес электронной почты должен быть уникальным для каждого студента. nullable=False указывает, что этот столбец не должен быть пустым.
  • age: Возраст студента.
  • created_at: Время создания записи студента в базе данных. Вы используете db.DateTime для определения его как объекта Python datetime. timezone=True включает поддержку часового пояса. server_default устанавливает значение по умолчанию в базе данных при создании таблицы, чтобы значения по умолчанию обрабатывались базой данных, а не моделью. Вы передаете ему функцию func.now(), которая вызывает функцию даты и времени SQL now(). В SQLite она отображается как CURRENT_TIMESTAMP при создании таблицы студентов.
  • bio: Биография студента. db.Text() указывает, что столбец содержит длинные тексты.

Смотрите документацию SQLAlchemy для типов столбцов, отличных от используемых в предыдущем блоке кода.

Специальная функция __repr__ позволяет задать строковое представление для каждого объекта для его распознавания в целях отладки. В данном случае вы используете имя студента.

Файл app.py будет выглядеть следующим образом:

flask_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func


basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

Сохраните и закройте app.py.

Создание базы данных

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

После активации вашего виртуального окружения установите файл app.py как ваше Flask-приложение, используя переменную среды FLASK_APP. Затем откройте оболочку Flask с помощью следующей команды в вашем каталоге flask_app:

  1. export FLASK_APP=app
  2. flask shell

A Python interactive shell will be opened. This special shell runs commands in the context of your Flask application, so that the Flask-SQLAlchemy functions you’ll call are connected to your application.

Импортируйте объект базы данных и модель студента, а затем запустите функцию db.create_all(), чтобы создать таблицы, связанные с вашими моделями. В этом случае у вас есть только одна модель, что означает, что вызов функции создаст только одну таблицу в вашей базе данных:

  1. from app import db, Student
  2. db.create_all()

Оставьте оболочку работающей, откройте еще одно окно терминала и перейдите в ваш каталог flask_app. Теперь вы увидите новый файл с именем database.db в flask_app.

Примечание:

Функция db.create_all() не создает или не обновляет таблицу, если она уже существует. Например, если вы измените свою модель, добавив новый столбец, и выполните функцию db.create_all(), изменение, которое вы внесли в модель, не будет применено к таблице, если она уже существует в базе данных. Решение состоит в удалении всех существующих таблиц базы данных с помощью функции db.drop_all(), а затем их повторном создании с помощью функции db.create_all(), вот так:

  1. db.drop_all()
  2. db.create_all()

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

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

Заполнение таблицы

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

Используйте ту же оболочку Flask, которую вы открыли ранее, или откройте новую с активированным виртуальным окружением в вашем каталоге flask_app:

  1. flask shell

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

  1. from app import db, Student
  2. student_john = Student(firstname='john', lastname='doe',
  3. email='[email protected]', age=23,
  4. bio='Biology student')

Объект student_john представляет студента, который будет добавлен в базу данных, но этот объект еще не был записан в базу данных. Посмотрите на объект в оболочке Flask, чтобы увидеть его строковое представление, которое вы сконструировали с помощью метода __repr__():

  1. student_john

Вы получите следующий вывод:

Output
<Student john>

Вы можете получить значение столбцов, используя атрибуты класса, которые вы определили в модели Student:

  1. student_john.firstname
  2. student_john.bio
Output
'john' 'Biology student'

Поскольку этот студент еще не был добавлен в базу данных, его ID будет None:

  1. print(student_john.id)
Output
None

Чтобы добавить этого студента в базу данных, сначала вам нужно добавить его в сессию базы данных, которая управляет транзакцией базы данных. Flask-SQLAlchemy предоставляет объект db.session, через который вы можете управлять изменениями в вашей базе данных. Добавьте объект student_john в сессию с помощью метода db.session.add(), чтобы подготовить его к записи в базу данных:

  1. db.session.add(student_john)

Это вызовет оператор INSERT, но вы не получите обратно ID, потому что транзакция базы данных все еще не подтверждена. Чтобы подтвердить транзакцию и применить изменение к базе данных, используйте метод db.session.commit():

  1. db.session.commit()

Теперь, когда студент Джон добавлен в базу данных, вы можете получить его ID:

  1. print(student_john.id)
Output
1

Вы также можете использовать метод db.session.add() для редактирования элемента в базе данных. Например, вы можете изменить электронную почту студента следующим образом:

  1. student_john.email = '[email protected]'
  2. db.session.add(student_john)
  3. db.session.commit()

Используйте оболочку Flask, чтобы добавить еще несколько студентов в вашу базу данных:

  1. sammy = Student(firstname='Sammy',
  2. lastname='Shark',
  3. email='[email protected]',
  4. age=20,
  5. bio='Marine biology student')
  6. carl = Student(firstname='Carl',
  7. lastname='White',
  8. email='[email protected]',
  9. age=22,
  10. bio='Marine geology student')
  11. db.session.add(sammy)
  12. db.session.add(carl)
  13. db.session.commit()

Теперь вы можете запросить все записи в таблице студентов, используя атрибут query с методом all():

  1. Student.query.all()

Вы получите следующий вывод:

Output
[<Student john>, <Student Sammy>, <Student Carl>]

На данный момент в вашей базе данных три студента. Далее вы создадите маршрут Flask для главной страницы и отобразите всех студентов из вашей базы данных на ней.

Шаг 3 — Отображение всех записей

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

Оставьте оболочку Flask запущенной и откройте новое окно терминала.

Откройте ваш файл app.py, чтобы добавить маршрут для главной страницы в него:

  1. nano app.py

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

flask_app/app.py

# ...

@app.route('/')
def index():
    students = Student.query.all()
    return render_template('index.html', students=students)

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

Здесь вы создаете функцию представления index(), используя декоратор app.route(). В этой функции вы запрашиваете базу данных и получаете всех студентов, используя модель Student с атрибутом query, который позволяет извлекать один или несколько элементов из базы данных с использованием различных методов. Вы используете метод all(), чтобы получить все записи студентов в базе данных. Вы сохраняете результат запроса в переменной с именем students и передаете его в шаблон с именем index.html, который вы рендерите, используя вспомогательную функцию render_template().

Прежде чем создавать файл шаблона index.html, на котором вы будете отображать существующих студентов в базе данных, сначала создайте базовый шаблон, в котором будет весь основной 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>
        .title {
            margin: 5px;
        }

        .content {
            margin: 5px;
            width: 100%;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
        }

        .student {
            flex: 20%;
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3;
            inline-size: 100%;
        }

        .bio {
            padding: 10px;
            margin: 5px;
            background-color: #ffffff;
            color: #004835;
        }

        .name a {
            color: #00a36f;
            text-decoration: none;
        }

        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

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

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

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

  1. nano templates/index.html

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

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

{% block content %}
    <h1 class="title">{% block title %} Students {% endblock %}</h1>
    <div class="content">
        {% for student in students %}
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
        {% endfor %}
    </div>
{% endblock %}

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

Здесь вы расширяете базовый шаблон и заменяете содержимое блока content. Вы используете заголовок <h1>, который также служит заголовком. Вы используете цикл Jinja for в строке {% for student in students %} для перебора каждого студента в переменной students, которую вы передали из функции представления index() в этот шаблон. Вы отображаете идентификатор студента, его имя и фамилию, электронную почту, возраст, дату добавления его в базу данных и его биографию.

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

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

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

  1. flask run

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

http://127.0.0.1:5000/

Вы увидите студентов, которых вы добавили в базу данных, на странице, аналогичной следующей:

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

Шаг 4 — Отображение одной записи

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

К концу этого шага URL http://127.0.0.1:5000/1 будет страницей, отображающей первого студента (потому что у него ID 1). URL http://127.0.0.1:5000/ID будет отображать запись с соответствующим номером ID, если она существует.

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

Откройте оболочку Flask для демонстрации запроса студентов:

  1. flask shell

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

Например, вы можете использовать метод filter_by() с параметром, таким как firstname, который сопоставляется с колонкой в таблице с аргументом, чтобы извлечь определенного студента:

  1. from app import db, Student
  2. Student.query.filter_by(firstname='Sammy').all()
Output
[<Student Sammy>]

Здесь вы извлекаете всех студентов с именем Sammy. Вы используете метод all(), чтобы получить список всех результатов. Чтобы получить первый результат, который здесь единственный, вы можете использовать метод first():

  1. Student.query.filter_by(firstname='Sammy').first()
Output
<Student Sammy>

Чтобы получить студента по его ID, вы можете использовать filter_by(id=ID):

  1. Student.query.filter_by(id=3).first()

Или вы можете использовать более короткий метод get(), который позволяет извлекать конкретный элемент с использованием его первичного ключа:

  1. Student.query.get(3)

Оба метода дадут одинаковый вывод:

Output
<Student Carl>

Теперь вы можете выйти из оболочки:

  1. exit()

Для получения студента по их идентификатору вы создадите новый маршрут, который отображает страницу для каждого отдельного студента. Вы будете использовать метод get_or_404(), предоставляемый Flask-SQLAlchemy, который является вариантом метода get(). Разница заключается в том, что get() возвращает значение None, когда ни один результат не соответствует заданному идентификатору, а get_or_404() возвращает ответ HTTP 404 Not Found. Откройте app.py для модификации:

  1. nano app.py

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

flask_app/app.py
# ...

@app.route('/<int:student_id>/')
def student(student_id):
    student = Student.query.get_or_404(student_id)
    return render_template('student.html', student=student)

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

Здесь вы используете маршрут '/<int:student_id>/', с int: как конвертером, который преобразует строку по умолчанию в URL в целое число. И student_id – это переменная URL, которая будет определять студента, которого вы отобразите на странице.

Идентификатор передается из URL в функцию представления student() через параметр student_id. Внутри функции вы запрашиваете коллекцию студентов и извлекаете студента по идентификатору, используя метод get_or_404(). Это сохранит данные студента в переменной student, если он существует, и ответит с ошибкой HTTP 404 Not Found, если студента с заданным идентификатором не существует в базе данных.

Вы отображаете шаблон с именем student.html и передаете ему полученного студента.

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

  1. nano templates/student.html

Введите следующий код в этот новый файл student.html. Этот файл будет похож на шаблон index.html, за исключением того, что он будет отображать только одного студента:

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

{% block content %}
    <span class="title">
        <h1>{% block title %} {{ student.firstname }} {{ student.lastname }}{% endblock %}</h1>
    </span>
    <div class="content">
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
    </div>
{% endblock %}

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

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

Используйте ваш браузер для перехода по URL второго студента:

http://127.0.0.1:5000/2

Вы увидите страницу, похожую на следующую:

Теперь отредактируйте index.html, чтобы каждое имя студента было ссылкой на их страницу:

  1. nano templates/index.html

Отредактируйте цикл for, чтобы он выглядел следующим образом:

flask_app/templates/index.html
{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
    </div>
{% endfor %}

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

Вы добавили тег <a> к полному имени студента, который ссылается на страницу студента с использованием функции url_for(), передавая идентификатор студента, который хранится в student.id, в функцию представления student().

Перейдите на вашу главную страницу или обновите ее:

http://127.0.0.1:5000/

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

После создания страницы для отдельных студентов вы следующим шагом добавите страницу для добавления новых студентов в базу данных.

Шаг 5 — Создание Новой Записи

На этом этапе вы добавите новый маршрут в ваше приложение для добавления новых студентов в базу данных с помощью веб-форм.

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

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

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

  1. nano app.py

Добавьте следующий маршрут в конец файла 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

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

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">{% block title %} Add a New Student {% endblock %}</h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  ></textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

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

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

У вас есть два текстовых поля с именами firstname и lastname. Вы будете использовать эти имена для доступа к данным формы, которые пользователь отправляет в вашу функцию представления позже.

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

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

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

http://127.0.0.1:5000/create

Вы увидите страницу Добавить нового студента с веб-формой и кнопкой Отправить, как показано ниже:

Если вы заполните форму и отправите ее, отправив 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':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']
        student = Student(firstname=firstname,
                          lastname=lastname,
                          email=email,
                          age=age,
                          bio=bio)
        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('create.html')

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

Вы обрабатываете POST-запросы внутри условия if request.method == 'POST'. Вы извлекаете имя, фамилию, электронную почту, возраст и биографию, которые пользователь отправляет из объекта request.form. Вы преобразуете возраст, который передается как строка, в целое число, используя функцию int() в Python. Вы создаете объект student с использованием модели Student. Вы добавляете объект студента в сеанс базы данных, затем фиксируете транзакцию.

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

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

http://127.0.0.1:5000/create

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

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

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

  1. nano templates/base.html

Отредактируйте тег <body>, изменив значение атрибута href для ссылки Создать:

flask_app/templates/base.html
<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>

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

Обновите вашу домашнюю страницу, и вы заметите, что ссылка Создать в панели навигации теперь функционирует.

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

Шаг 6 — Редактирование записи

На этом этапе вы добавите новую страницу в ваше приложение для редактирования данных существующих студентов. Вы добавите новый маршрут /ID/edit/ для редактирования данных студентов на основе их ID.

Откройте app.py:

  1. nano app.py

Добавьте следующий маршрут в конце файла. Этот маршрут извлекает запись студента, которую вы хотите отредактировать, используя его ID. Он извлекает новые данные студента, отправленные через веб-форму, которую вы создадите позже. Затем он редактирует данные студента и перенаправляет пользователя на главную страницу:

flask_app/app.py
# ...


@app.route('/<int:student_id>/edit/', methods=('GET', 'POST'))
def edit(student_id):
    student = Student.query.get_or_404(student_id)

    if request.method == 'POST':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']

        student.firstname = firstname
        student.lastname = lastname
        student.email = email
        student.age = age
        student.bio = bio

        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('edit.html', student=student)

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

Здесь у вас есть маршрут /<int:student_id>/edit/, который принимает как методы POST, так и GET, с переменной URL student_id, которая передает ID в функцию представления edit().

Вы используете метод запроса get_or_404() на модели Student, чтобы получить студента, связанного с заданным идентификатором студента. В случае отсутствия студента с указанным идентификатором в базе данных будет возвращена ошибка 404 Not Found.

Если заданный идентификатор связан со студентом, выполнение кода продолжается до условия if request.method == 'POST'. Если запрос был типа GET, что означает, что пользователь не отправил форму, то это условие ложно, и код внутри него будет пропущен до строки return render_template('edit.html', student=student). Это рендерит шаблон edit.html, передавая ему объект студента, полученного из базы данных, что позволяет заполнить веб-форму студента текущими данными студента. Вы создадите этот шаблон edit.html позже.

Когда пользователь редактирует данные студента и отправляет форму, выполняется код внутри if request.method == 'POST'. Вы извлекаете отправленные данные студента из объекта request.form в соответствующие переменные. Вы устанавливаете каждый атрибут объекта student в новые отправленные данные, чтобы изменить значения столбцов, как вы делали в Шаге 2. Если никаких изменений не было внесено в поле веб-формы, значение этого столбца останется прежним в базе данных.

После установки данных студента в новые отправленные данные вы добавляете объект student в сессию базы данных, затем фиксируете изменения. Наконец, перенаправляете пользователя на главную страницу.

Далее вам необходимо создать страницу, где пользователи смогут вносить изменения. Откройте новый шаблон edit.html:

  1. nano templates/edit.html

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

flask_app/templates/edit.html

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">
        {% block title %} Edit {{ student.firstname }}
                               {{ student.lastname }}'s Details
        {% endblock %}
    </h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   value={{ student.firstname }}
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   value={{ student.lastname }}
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   value={{ student.email }}
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   value={{ student.age }}
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  >{{ student.bio }}</textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

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

Заголовок содержит имя и фамилию студента. Атрибут value каждого поля ввода и значение текстовой области биографии устанавливаются в соответствующее значение в объекте student, который вы передали из функции edit() в шаблон edit.html.

Теперь перейдите по следующему URL, чтобы изменить данные первого студента:

http://127.0.0.1:5000/1/edit

Вы увидите страницу, аналогичную следующей:

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

Затем вы добавите кнопку Изменить под каждым студентом на главной странице для перехода на их страницу редактирования. Откройте файл шаблона index.html:

  1. nano templates/index.html

Измените цикл for в этом файле index.html, чтобы он выглядел точно следующим образом:

flask_app/templates/index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>
    </div>
{% endfor %}

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

Здесь вы добавляете тег <a> для перехода к функции представления edit(), передавая значение student.id для перехода на страницу редактирования каждого студента с ссылкой Изменить.

Теперь у вас есть страница для редактирования существующих студентов. Далее вы добавите кнопку Удалить для удаления студентов из базы данных.

Шаг 7 — Удаление записи

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

Сначала добавьте новый маршрут /id/delete, который принимает POST-запросы. Ваша новая функция представления delete() получит идентификатор студента, которого вы хотите удалить, передаст идентификатор в метод запроса get_or_404() модели Student, чтобы получить его, если он существует, или ответит страницей 404 Not Found, если студент с указанным идентификатором не был найден в базе данных.

Откройте app.py для редактирования:

  1. nano app.py

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

flask_app/app.py

# ...

@app.post('/<int:student_id>/delete/')
def delete(student_id):
    student = Student.query.get_or_404(student_id)
    db.session.delete(student)
    db.session.commit()
    return redirect(url_for('index'))

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

Здесь, вместо обычного декоратора app.route, вы используете декоратор app.post, введенный в Flask версии 2.0.0, который добавил ярлыки для распространенных методов HTTP. Например, @app.post("/login") является ярлыком для @app.route("/login", methods=["POST"]). Это означает, что эта функция представления принимает только запросы POST, и переход по маршруту /ID/delete в вашем браузере приведет к ошибке 405 Метод не разрешен, потому что веб-браузеры по умолчанию используют запросы GET. Чтобы удалить студента, пользователь нажимает на кнопку, которая отправляет POST-запрос на этот маршрут.

Эта функция представления delete() получает ID студента, который должен быть удален, через переменную URL student_id. Вы используете метод get_or_404() для получения студента и сохранения его в переменной student, или отвечаете 404 Not Found, если студент не существует. Вы используете метод delete() на сессии базы данных в строке db.session.delete(student), передавая ему объект студента. Это настраивает сеанс для удаления студента при выполнении транзакции. Поскольку вам не нужно выполнять какие-либо другие изменения, вы непосредственно фиксируете транзакцию, используя db.session.commit(). Наконец, вы перенаправляете пользователя на главную страницу.

Затем отредактируйте шаблон index.html, чтобы добавить кнопку Удалить студента:

  1. nano templates/index.html

Измените цикл for, добавив новый тег <form> непосредственно под ссылкой Edit:

flask_app/templates/index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>

        <hr>
        <form method="POST"
                action="{{ url_for('delete', student_id=student.id) }}">
            <input type="submit" value="Delete Student"
                onclick="return confirm('Are you sure you want to delete this entry?')">
        </form>

    </div>
{% endfor %}

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

Здесь у вас есть веб-форма, которая отправляет POST-запрос на функцию представления delete(). Вы передаете student.id в качестве аргумента для параметра student_id, чтобы указать запись студента для удаления. Вы используете функцию confirm(), доступную в веб-браузерах, для отображения сообщения подтверждения перед отправкой запроса.

Теперь обновите вашу индексную страницу.

Вы увидите кнопку Delete Student под каждой записью студента. Нажмите на неё и подтвердите удаление. Вы будете перенаправлены на индексную страницу, и студент больше не будет там.

Теперь у вас есть способ удаления студентов из базы данных в вашем приложении управления студентами.

Заключение

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

Использование SQLAlchemy в вашем приложении позволяет вам использовать классы и объекты Python для управления вашей базой данных SQL. Вместо SQLite вы можете использовать другой движок базы данных, и кроме конфигурации SQLALCHEMY_DATABASE_URI, отвечающей за соединение, вам не нужно ничего менять в коде вашего приложения. Это позволяет вам переходить от одного движка SQL базы данных к другому с минимальными изменениями кода. Дополнительную информацию смотрите в документации Flask-SQLAlchemy.

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

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-flask-sqlalchemy-to-interact-with-databases-in-a-flask-application