Как ORM Ormar обнаруживает и регистрирует все определенные модели

Ответ

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

Процесс выглядит следующим образом:

  1. Наследование: Когда вы определяете свою модель, например class Book(ormar.Model):, она наследует функциональность ormar.Model.
  2. Работа метакласса: В ormar.Model встроен метакласс, который «перехватывает» момент создания нового класса (например, Book).
  3. Регистрация: В этот момент метакласс анализирует класс, его поля (аннотации типов) и вложенный класс Meta, после чего добавляет информацию о новой модели в специальный глобальный реестр — ormar.Model.MetaRegistry.

Пример

import databases
import sqlalchemy
import ormar

metadata = sqlalchemy.MetaData()
database = databases.Database("sqlite:///db.sqlite")

class BaseMeta(ormar.ModelMeta):
    metadata = metadata
    database = database

# При определении этих классов, они автоматически регистрируются
class Author(ormar.Model):
    class Meta(BaseMeta):
        tablename = "authors"

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)

class Book(ormar.Model):
    class Meta(BaseMeta):
        tablename = "books"

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=100)
    author: Author = ormar.ForeignKey(Author)

Практическое применение

Этот механизм автоматической регистрации необходим для:

  • Генерации SQL: metadata.create_all(engine) использует собранные в metadata данные для создания таблиц.
  • Миграций: Инструменты вроде Alembic могут использовать metadata для автоматического создания миграций.
  • Построения схемы API: В FastAPI Ormar использует этот реестр для генерации Pydantic-схем.

Получить список всех зарегистрированных моделей можно программно:

all_models = ormar.Model.MetaRegistry.get_models()
# -> вернет список классов [Author, Book]

Ответ 18+ 🔞

Ах ты ж ёпта, ну и история с этими метаклассами в Ormar! Сидишь ты такой, пишешь модельку, а под капотом-то, блядь, целый театр разворачивается, ёперный театр!

Вот смотри, как это работает, чтоб тебя чих-пых в сраку. Ты объявляешь свой класс, типа class Book(ormar.Model):, и думаешь: «Ну, обычное наследование, чё тут такого». А на самом деле, сука, в этот самый момент включается метакласс, который вшит в ormar.Model. Этот метакласс — он как хитрая жопа, которая подглядывает за тобой в замочную скважину, когда ты новый класс создаёшь.

И что он делает? Он хватает твой свежеиспечённый класс Book, начинает его шарить по карманам: смотрит на все поля, которые ты наобъявлял, выковыривает оттуда вложенный класс Meta с настройками. А потом, блядь, как шпион, заносит всю эту информацию в секретный реестр — в ormar.Model.MetaRegistry. Всё, модель зарегистрирована, теперь она в системе, её никуда не денешь!

Пример, чтобы совсем понятно стало

import databases
import sqlalchemy
import ormar

metadata = sqlalchemy.MetaData()
database = databases.Database("sqlite:///db.sqlite")

class BaseMeta(ormar.ModelMeta):
    metadata = metadata
    database = database

# Вот тут, когда эти классы определяются, они автоматом в реестр попадают!
class Author(ormar.Model):
    class Meta(BaseMeta):
        tablename = "authors"

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)

class Book(ormar.Model):
    class Meta(BaseMeta):
        tablename = "books"

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=100)
    author: Author = ormar.ForeignKey(Author)

А нахуя это всё, спросишь ты?

А вот нахуя, мой друг:

  • Чтобы SQL сгенерить. Когда ты вызываешь metadata.create_all(engine), эта самая metadata уже знает про все твои модели, потому что они в неё записались через этот реестр. И создаёт таблицы, не спрашивая.
  • Для миграций. Инструменты вроде Alembic смотрят в эту metadata и говорят: «О, тут новые поля появились, надо миграцию накатить». Красота, блядь!
  • Для API. FastAPI с Ormar'ом использует этот реестр, чтобы на лету Pydantic-схемы для запросов и ответов сгенерить. Удобно, ёпта!

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

all_models = ormar.Model.MetaRegistry.get_models()
# Вернёт тебе список: [<class 'Author'>, <class 'Book'>]

Вот так вот, сука. Кажется, просто наследуешься от класса, а под капотом — целая операция по сбору разведданных и занесению в базу. Красиво, чё.