Ответ
Ormar использует метаклассы для автоматического обнаружения и регистрации всех моделей, которые наследуются от базового класса ormar.Model.
Процесс выглядит следующим образом:
- Наследование: Когда вы определяете свою модель, например
class Book(ormar.Model):, она наследует функциональность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()
# -> вернет список классов [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'>]
Вот так вот, сука. Кажется, просто наследуешься от класса, а под капотом — целая операция по сбору разведданных и занесению в базу. Красиво, чё.