Flask-SQLAlchemy — Проектирование моделей базы данных

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


Зачем использовать ORM?

Написание SQL-инструкций напрямую для работы с базой данных утомительно и чревато ошибками.

ORM (объектно-реляционное отображение)Он позволяет определять структуры таблиц с помощью классов Python и манипулировать данными с помощью методов Python.

Flask-SQLAlchemy — это интеграция SQLAlchemy с Flask, которая оборачивает типовые операции и упрощает конфигурацию.


Установка и настройка

(venv) $ pip install flask-sqlalchemy

Пример

# Путь к файлу: app.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)

# Путь к файлу базы данных SQLite (расположен в корневом каталоге проекта)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db'
# Отключить отслеживание изменений (экономит память; в будущих версиях будет отключено по умолчанию)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Создать экземпляр db и привязать его к app
db = SQLAlchemy(app)

sqlite:///blog.dbТри косые черты в нём указывают на относительный путь. База данных SQLite — это просто файл, для которого не требуется устанавливать программное обеспечение базы данных, что делает её идеальной для разработки и тестирования.


Определение моделей: Post и Category

Пример

# Путь к файлу: models.py
from datetime import datetime
from app import db

class Category(db.Model):
    """Категория статьи"""
    __tablename__ = 'categories'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(50), unique=True, nullable=False)
    slug = db.Column(db.String(50), unique=True, nullable=False)
    # backref: В объекте Category можно использовать .posts, чтобы получить все его статьи в обратном порядке.
    posts = db.relationship('Post', backref='category', lazy='dynamic')

    def __repr__(self):
        return f'<Category {self.name}>'


class Post(db.Model):
    """Запись блога"""
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(200), nullable=False)
    slug = db.Column(db.String(200), unique=True, nullable=False)
    summary = db.Column(db.Text, default='')
    content = db.Column(db.Text, nullable=False)
    # Внешний ключ: db.ForeignKey('table_name.field_name')
    category_id = db.Column(db.Integer, db.ForeignKey('categories.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    def __repr__(self):
        return f'<Post {self.title}>'

Распространённые типы полей

Тип поляТип в базе данныхОбщие параметры
db.IntegerINTEGERprimary_key, autoincrement
db.String(N)VARCHAR(N)unique, nullable, default
db.TextTEXTdefault
db.DateTimeDATETIMEdefault, onupdate
db.BooleanBOOLEANdefault
db.ForeignKey('table.field')FOREIGN KEY—

Создание таблицы базы данных

В отличие от migrate в Django, Flask требует ручной инициализации таблиц базы данных.

(venv) $ flask shell                        # 进入 Flask 交互式 Shell

Пример

# Введите в flask shell
from app import db
db.create_all()     # Создать таблицы базы данных для всех моделей
exit()

После выполнения в корневом каталоге проекта будет создано следующееblog.dbФайл.

db.create_all()Создаёт таблицу, только если она не существует. Если вы измените структуру модели (например, добавив новые поля), таблица не обновится автоматически. В продакшене следует использовать Flask-Migrate (глава 5) для управления изменениями структуры.


Используйте flask shell для вставки тестовых данных.

Пример

# Введите в flask shell
from app import db
from models import Category, Post

# 1. Создайте категорию
py_cat = Category(name='Python', slug='python')
css_cat = Category(name='CSS', slug='css')
flask_cat = Category(name='Flask', slug='flask')
db.session.add_all([py_cat, css_cat, flask_cat])
db.session.commit()

# 2. Создание статьи
post1 = Post(
    title='Полное руководство по Flask для начинающих',
    slug='flask-beginner-guide',
    summary=Изучите Flask с нуля, охватывая основные концепции, такие как маршрутизация, шаблоны, ORM.,
    content=<h2>Почему стоит изучать Flask?</h2><p>Flask — самый гибкий веб-микрофреймворк в Python...</p>,
    category=flask_cat
)
post2 = Post(
    title=Сопрограммы Python: объяснение,
    slug='python-coroutine',
    summary=Разберитесь с asyncio, корутинами и циклами событий в одной статье.,
    content=<h2>Что такое корутина?</h2><p>Корутина — это более лёгкое решение для конкурентности, чем потоки...</p>,
    category=py_cat
)
post3 = Post(
    заголовок=Практическое руководство по CSS Grid Layout,
    slug='css-grid-layout',
    краткое описание=Легко реализуйте сложные адаптивные макеты с помощью CSS Grid.,
    содержание=<h2>Начало работы с Grid</h2><p>Grid — это двумерная система компоновки...</p>,
    category=css_cat
)
db.session.add_all([post1, post2, post3])
db.session.commit()

# 3. Проверка запросов
print(Post.query.all())
print(Post.query.filter(Post.category_id == 1).all())

Основные запросы Flask-SQLAlchemy

МетодыЭквивалентный SQLВозвращаемое значение
Post.query.all()SELECT * FROM postsСписок
Post.query.get(1)WHERE id = 1Один объект или None
Post.query.get_or_404(1)WHERE id = 1Один объект или автоматически возвращает 404
Post.query.filter_by(category_id=1).all()WHERE category_id=1Список
Post.query.filter(Post.title.ilike('%flask%')).all()WHERE title LIKE '%flask%'Список
Post.query.order_by(Post.created_at.desc()).all()ORDER BY created_at DESCСписок

Итоги главы

В этой главе вы освоили полный рабочий процесс Flask-SQLAlchemy: установку и настройку SQLALCHEMY_DATABASE_URI, определение моделей с помощью db.Model (типы полей/внешние ключи/relationship), инициализацию таблиц с помощью db.create_all() и вставку и запрос данных в оболочке flask shell.

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

Другие расширения