JavaRush /Курси /Модуль 4: FastAPI /Створення моделей даних з використанням SQLAlchemy

Створення моделей даних з використанням SQLAlchemy

Модуль 4: FastAPI
Рівень 6 , Лекція 2
Відкрита

Моделі даних можна впевнено назвати основою застосунку. Саме вони визначають форму і структуру даних, з якими він буде працювати. А SQLAlchemy — це такий зручний спосіб опису цих моделей за допомогою Python-класів. При цьому SQLAlchemy спроєктований так, що вам — розробнику — не потрібно фокусуватися на складнощах SQL, можна зосередитись на логіці.

Як класи в ООП, моделі даних нагадують форми для печива. Ви визначаєте "форму" (тобто модель) один раз, а потім використовуєте її для створення багатьох однотипних "печив" (тобто конкретних записів у базі даних).


Основи створення моделей

Кожна модель SQLAlchemy — це клас, який наслідується від базового класу Base. Цей базовий клас відповідає за зв'язок моделі з таблицею в базі даних. В SQLAlchemy для створення Base використовується конструкція:


from sqlalchemy.orm import declarative_base

Base = declarative_base()

Давайте створимо нашу першу модель — модель користувача (User).


from sqlalchemy import Column, Integer, String

class User(Base):
    __tablename__ = 'users'  # Вказуємо ім'я таблиці

    id = Column(Integer, primary_key=True)  # Первинний ключ
    name = Column(String, nullable=False)  # Стовпець для імені
    email = Column(String, unique=True, nullable=False)  # Унікальний і обов'язковий стовпець

    def __repr__(self):
        return f"<User(name={self.name!r}, email={self.email!r})>"

Що ми зробили:

  • Вказали ім'я таблиці через __tablename__.
  • Визначили поля таблиці (стовпці) як атрибути класу, використовуючи Column.
  • Додали типи даних для кожного стовпця (Integer, String).
  • Реалізували метод __repr__ для зручнішого відображення об'єкта.

Тепер модель User представляє таблицю users в нашій базі даних.


Визначення таблиць і стовпців

У таблицях бази даних є різні типи даних. SQLAlchemy підтримує багато типів: Integer, String, Float, Boolean, DateTime та інші. Давайте розберемося, як використовувати ці типи і додавати додаткові поля.

Припустимо, наша модель користувача також повинна зберігати дату реєстрації і статус, який вказує, чи активний користувач. Додамо їх:


from sqlalchemy import Boolean, DateTime
from datetime import datetime

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    email = Column(String, unique=True, nullable=False)
    is_active = Column(Boolean, default=True)  # Булеве значення за замовчуванням
    registered_at = Column(DateTime, default=datetime.utcnow)  # Використовуємо поточну дату

    def __repr__(self):
        return f"<User(name={self.name!r}, email={self.email!r})>"

Тепер таблиця users міститиме два нових стовпці:

  • is_active — булеве значення для статусу активності;
  • registered_at — дата і час реєстрації.

Приклад створення складної моделі

Реальне життя — це не тільки "ім'я" і "email". Ваші моделі можуть бути складними, включаючи обмеження, індекси і навіть користувацькі типи даних. Давайте створимо модель для продуктів, що включає ціну і категорію.


from sqlalchemy import ForeignKey, Float

class Product(Base):
    __tablename__ = 'products'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    price = Column(Float, nullable=False)
    category_id = Column(Integer, ForeignKey('categories.id'))  # Зовнішній ключ для категорії

    def __repr__(self):
        return f"<Product(name={self.name!r}, price={self.price!r})>"

Ця модель показує:

  1. Як використовувати тип Float для збереження чисел з плаваючою крапкою.
  2. Як пов'язати модель з іншою таблицею через ForeignKey.

Створення пов'язаних таблиць

Для повноти картини нам потрібно створити таблицю categories, на яку посилається Product.


class Category(Base):
    __tablename__ = 'categories'

    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False, unique=True)

    def __repr__(self):
        return f"<Category(name={self.name!r})>"

Тепер у нас є модель Category, до якої прив'язані продукти. Ми зможемо створювати категорії і зв'язувати їх з товарами.


Опрацювання обмежень та індексів

SQLAlchemy дозволяє додавати обмеження, такі як унікальність (unique) або умова обов'язкової присутності даних (nullable=False). Додамо індекс на поле email в моделі користувача:


from sqlalchemy import Index

Index('idx_email', User.email)  # Створення індекса

Індекси прискорюють пошук певних даних, наприклад електронної пошти. Це особливо важливо для полів, які часто використовуються в запитах.


Практична демонстрація

Давайте створимо невелику базу даних SQLite і створимо таблиці на основі наших моделей.


from sqlalchemy import create_engine

# Підключення SQLite (або іншої бази даних)
engine = create_engine('sqlite:///example.db', echo=True)  # echo=True для логування SQL

# Створення всіх таблиць
Base.metadata.create_all(engine)

print("Таблиці успішно створені!")

Після виконання коду ми побачимо детальні логи виконання SQL-запитів для створення таблиць.


Навіщо це потрібно?

Чому ми використовуємо ORM і SQLAlchemy замість ручного написання SQL? Тому що ORM:

  1. Спрощує читання та підтримку коду.
  2. Дозволяє абстрагуватися від конкретної бази даних.
  3. Автоматизує багато рутинних задач, таких як перетворення даних між Python і SQL.

У реальних проєктах моделі допомагають розробникам швидко додавати нові фічі, забезпечувати цілісність даних і уникати складнощів при міграції на іншу базу даних.

SQLAlchemy, на відміну від Django ORM, дає більше контролю над SQL-запитами. Це робить його відмінним вибором для складних проєктів.


Типові помилки

  1. Пропущений __tablename__. Якщо забути вказати ім'я таблиці, SQLAlchemy не зрозуміє, як зв'язати модель з таблицею.
  2. Невідповідність типів даних. Переконайтеся, що типи даних у моделі відповідають типам у базі даних. Наприклад, String повинен мати обмеження довжини для сумісності з деякими базами.
  3. Відсутність первинного ключа. Кожна таблиця повинна мати принаймні один первинний ключ (зазвичай поле id).

Підсумкова структура проєкту

На цьому етапі в нас є:

  1. Таблиця користувачів (User), що включає ім'я, email, активність і дату реєстрації.
  2. Таблиця продуктів (Product) з ціною і категорією.
  3. Таблиця категорій (Category) для зв'язку.

У наступній лекції ми продовжимо розбиратися з полями і типами даних, включаючи кастомні типи, обмеження та валідації.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ