📘
Dev & Ops
Programming
Programming
  • Programming Book
  • Technologies
    • API
      • Известные API
        • Facebook API
      • Проектирование API
        • Программы для проектирования
          • Конвертация между форматами
          • Postman
          • Swagger
        • Webhooks
        • GraphQL
          • Введение
          • Introspection
        • RPC
          • Описание
          • gRPC
          • XML-RPC
          • SOAP
            • About
            • wsdl
          • JSON RPC
        • REST API
        • SAML
      • Program's API
        • Общие понятия
        • DOM API & элементы веб-браузера
        • Известные API
          • Google API
          • Telegram Bot API
      • Получение данных с сервера / AJAX
      • Хранение данных на стороне клиента
        • Подходы
        • Подробнее
          • Web Storage API
          • IndexedDB
          • Service Worker API
          • Cache API
    • WEB
      • Modern Web Application Architecture
      • PWA
      • Стеки технологий
        • JAMstack
        • LAMP
        • MEAN
        • MERN
      • The World Wide Web Consortium (W3C)
    • Архитектура сервисов
      • No-code / Low-code
        • Databases
        • Платформы для запуска и исполнения произвольных процессов и вычислений
        • Генераторы сайтов
      • Архитектурные паттерны
        • Papers
        • Инструменты визуализации и моделирования архитектуры
        • Архитектура проекта
          • Альтернативы
          • Feature-Sliced Design
          • MVC
          • DDD | Domain-Driven Design
          • Clean Architecture
          • Hexagonal
        • Архитектура кода
          • Papers
          • Singleton
          • Retry
          • Circuit Breaker
          • Общение между компонентами
            • Intro
            • Observer
            • PubSub
          • ООП
        • Архитектура систем
          • Monolith
          • API Gateway
          • CQRS
          • Microservices
          • Service Mesh
            • Для чего
            • Kuma
            • Istio
            • Hashicorp Consul
      • Telemetry
        • OpenTelemetry Concepts
        • Metrics
        • Tracing
        • Logs collect
      • Testing
      • Построение админок
      • Cases
      • Брокеры сообщений
        • Why?
        • RabbitMQ
        • RedisMQ
        • AWS SQS
        • Apache Kafka
        • ZeroMQ
        • Apache ActiveMQ
        • IronMQ
      • Автоматизация сборок
        • Makefile
      • Subscriptions
      • Zero Trust
    • Визуализация информации
      • Design/Совместная разработка интерфейсов
      • Работа с данными
      • Схемы, графы, рисунки..
        • Работа с графами
        • Рисуем структуру базы
        • Miro App
        • Рисование детских диаграмм
        • draw.io
        • Xmind
      • Куда заливать видео
      • yEd
      • LaTeX + PGF/TikZ
    • Version Control Systems
      • Git
      • Github
    • Programs
      • Adobe Alternatives
      • Atlassian
        • Jira
        • Confluence
      • Базы данных
        • LevelDB
      • Google Products for Developers
      • Open source
      • Фреймворки
      • vscode
      • Сборка проектов
      • Regular expressions
      • Browsers
    • Библиотеки
      • Полнотекстовой поиск
      • Парсинг грамматик
      • Регулярные выражения
      • Решение практических проблем ML
      • Chrome Cast
    • AI
      • Учимся использовать AI
      • Core Tech
      • Практическое использование
        • Assistants
        • Code assistants
        • Security
        • Web & Design
    • Dev portals
    • Разработка игр
  • Management
    • (draft) Product Management
      • Проработка идеи нового сервиса
      • Построение гипотез
    • Goals management
      • Определения и тезисы
      • OKR
      • KPI
      • OKR vs KPI
  • Programming Languages
    • Learn materials
    • Code Quality
    • Security Coding Styles
    • Testing
      • Integration testing
    • Other non programming languages
      • YAML
      • Proto
      • SQL
        • Create table
        • WITH operator
        • Time sleep
    • Bash
      • Простые операции
        • Работа с файлами
        • Untitled
        • trim
      • Процессы
    • PowerShell
      • IDE
      • Запуск скриптов
      • Удаленный запуск скриптов (with privesc)
      • Копирование файлов и директорий
      • Основы/Описание команд некоторых
      • Papers & Books
      • Примеры
        • Get-Help
        • Скачать файл
        • Импорт модулей и скриптов
        • Создание объекта Credential
        • Пользователи
        • Simple HTTP Server
    • Swift
    • ActionScript
    • Backend
      • Build & Distribution
        • cookiecutter
        • meson
        • Fastlane
        • Maven
        • Gradle
        • Apache Ant
      • JVM
        • Java Env Manager
        • Java
          • Build and Run Simple Script
          • jshell & jrunscript
          • Basic Serialization and Deserialization Java Object
          • Libraries
        • Scala
        • Kotlin
          • Intro
          • Basics
          • Async Programming
          • Логирование
          • Frameworks
            • Kotlin stdlib
            • HTTP
            • Documentation
        • Frameworks
          • Jersey Rest API
          • Spring Framework
            • About
            • Spring Boot AutoConfiguration
            • Spring IoC
            • Spring MVC
            • Spring Boot
            • Other Spring Annotations
          • Struts 2
        • Security
      • JS/TS
        • Lerna
        • Gulp
        • Frameworks
          • Templating libraries
          • Nest.js
          • Fastify
          • Express.js
          • Koa.js
      • Go
        • Get Started
          • Basic
          • Golang документация
          • Golang VSCode IDE
          • GOPATH and GOROOT
          • Сценарии на Go
        • Общее
          • Операторы и встроенные функции
          • Указатели и ссылки
          • Типизация
            • Простые типы
            • Составные типы
            • Пользовательские типы
            • Сокращенное и полное объявление переменной или константы
            • Строки
            • Срезы
            • Работа с типами
          • Коллекции
            • Перечисления
            • Массивы и срезы
            • Отображения
          • Процедурное программирование
            • Ветвления
              • if
              • select
              • switch
            • Циклы
            • Функции и методы
          • ООП
            • Ключевые понятия
            • Интерфейсы
            • Нюансы и ограничения
          • Generics in Go
          • Параллельное программирование
            • go-подпрограммы
            • Каналы обмена данными
            • Проблемы в параллельном программировании и пути их решения
        • Packages
          • Установка пакетов
          • Импортирование локальных пакетов
          • Базовые
            • Списком
            • context
          • Сторонние
            • Общепризнанные
            • Абстракции
            • Микросервисы
              • go-micro
              • gRPC Ecosystem
              • Go kit
                • About
                • Пример
                • Middlewares
                • Общение с другими микросервисами
            • GUI Decktop
            • web
            • Protocols
            • Network
            • FileSystem
            • Files & Databases
            • Testing, Profiling
            • Others
        • Debugging
        • Testing
        • Diagnostics
        • Godoc
        • Books
        • Примеры
          • Hello world
          • Узнать ОС
          • Типы
          • Файлы
          • HTTP-сервер
          • Test HTTP Request
          • RabbitMQ with Go
        • Проблемы
          • _cgo_export.c:3:10: fatal error: 'stdlib.h' file not found
        • Tools Powered on Go
        • Go Security
      • Ruby
        • Use Ruby Env and Deps
        • VSCode Ruby extensions
        • Ruby Language Guide
          • Comments
          • Variables
          • Strings
          • Ranges
          • Arrays
          • Methods
          • Flow Control
          • Classes
          • Dependencies
        • Cases
          • WebSocket Server
        • Frameworks
          • Web: Sinatra
          • Web: Padrino
          • Web: Ruby on Rails
            • Getting Started
            • Routes
            • Controllers
            • Modules
            • Rails Security
              • Common Security Issues
                • Common
                • Deserialisation
                • SQLi
              • Ruby CVEs
              • Security Tools
              • Papers
          • Middleware: Rack
          • Test: RSpec
      • Python
        • Basic
          • Install
          • Enum
          • Collections
          • Operators
          • Reflection
          • Tips
        • Advanced
          • Venv
          • Include Other Languages Libs
          • Время выполнения операции
          • Работа с контекстом
          • Работа с текстом, числами и объектами
          • Работа с файлами и IO
          • Запуск других программ
          • Работа с функциями
          • Работа с классами
          • Работа с итераторами
          • Работа с генераторами
          • Работа с многопоточностью
          • Создание CLI
          • tqdm
          • pydantic
        • Packaging
          • Intro
          • Install packages / Build Frontends
            • pip
            • pipx
            • hatch
            • poetry
          • Организация кода
            • src-layout vs flat-layout
            • namespaces
            • Plugins
          • Конфигурация
            • Papers
            • pyproject.toml
            • setup.py
            • setup.cfg
        • Packages
          • Public Lists of Python Packages
          • Linters
          • True Python
          • Network
          • Web
            • Simple HTTP Server
            • ASGI Python Web Servers
            • Http Client
              • aiohttp
              • requests
              • Packages
            • selenium
            • zeep [SOAP]
          • Web Frameworks
            • Bootle
            • FastAPI
            • Flask
            • Django
              • Intro
              • Django Admin
              • Django Signals
              • Security
            • Tornado
          • Databases
            • boto3
            • Mongo
            • Postgres
            • SQLAlchemy
          • Асинхронная обработка сообщений / работа с очередями
            • Celery
            • Others
          • Обработка информации
            • Работа с графами
            • plist
            • HAR
            • Лингвистика
            • Обработка изображений
            • Parsing HTML
            • Parsing JS
            • Beatifiers
            • XML -> Dictionary
            • Извлечение текста из pdf
            • Санитайзеры
            • Document converter
            • Генерация PDF документов
            • Parse and generate CSS
            • PDF Parser
          • Qt/QML
          • Python script -> binary file
          • Разное
          • Math & Crypto
          • Работа с другими сервисами
          • pwn & re
        • Patterns
          • Singleton
          • Factory
        • Testing
          • Intro
          • Pytest CLI
          • Markers
          • Fixtures
          • Mocking
          • Plugins
          • Configuration
          • Unit tests
        • Errors
        • Papers & Books
        • Python Security
      • .Net
        • dotnet
        • NuGet
        • Интроспекция .Net решения
      • ASP.NET
        • Поднимаем тестовое приложение
        • Структура папок ASP.Net проекта
          • ASP.NET Core
          • ASP.NET MVC
          • Classic ASP.NET WebApp
        • ASPX
          • examples
            • Hello world
        • Security
      • Perl
        • cpan
      • PHP
        • Getting Started
        • Basic
        • Magic Methods
        • Examples
          • Phar
          • Работа с файлами
          • Usefull small examples
          • Поднять инфру для разработки
          • Simple page with GET param
        • Packages
        • Frameworks
          • Yii
          • Laravel
            • Intro
            • Getting Started
            • Docker
            • Pentest
          • Zend
          • Symfony
          • CodeIgniter
          • Moodle
        • Libraries
        • Security
      • C/C++
        • Security
        • IDE
        • Build
          • Compilers
            • GCC
            • MinGW
            • Clang
            • MSVC
          • cmake
        • Cases
          • Как подключить .Lib/.h статическую библиотеку в свой проект VS/C/C++
          • Disable stdafx and other features in VS
          • Если не компилируются стандартные библиотеки в Visual Studio 2015
    • Frontend
      • Инструменты
      • HTML
        • Введение
        • Примеры
          • iframe
          • Страница со ссылкой
          • Сворачиваемый блок кода
          • Перейти на другую страницу по нажатии кнопки
          • Элементы, которые могут содержать ссылки
          • GET-запрос
          • Форматирование: оборачивание входного текста в блок (например при чтении локально файла или кода)
          • Random Color для всех элементов
        • Papers & Notes
      • CSS
        • Basic
        • Селекторы
          • О селекторах
          • Наследование стилей
          • Объявление и приоритеты
          • Псевдоклассы
        • CSS Свойства
          • Цвет
          • Шрифты и типографика
          • Стилизация абзацев
          • Блочная модель и отступы
          • Строчные и блочно-строчные элементы
          • Размеры элементов
          • Тени
          • Прокрутка элементов
          • Rotation
        • CSS Processors
        • Переменные
        • Браузерные стили
        • Стратегии верстки
          • Блочная и табличная верстки
          • Блочная верстка
          • Flexbox верстка
          • Grid Layout верстка
        • Frameworks
          • Gravity UI
          • Material Design
          • Materialize
          • Bootstrap
        • Советы
        • Papers
      • JS/TS
        • JavaScript
          • About
          • Basic JS
          • Async JS
          • RxJs
          • Guide
            • Proxy
            • Reflect
          • Cases
            • Борьба с CORS и Local File Read в браузере
            • Корректно нормализируем пути в JS
            • Тестирование работы с медленными ответами (slow js http response)
            • JSessionID
            • RCE
            • Замер времени отработки запроса
            • Периодические операции
            • postMessage
            • Самый простой редирект на странице
            • HTTP запросы и обработка ответов из JS
            • Использование сторонних скриптов
            • Отображение результатов списком
        • TypeScript
          • Init
          • Типы
            • Abstract classes, interfaces and types
            • Базовые типы и создание своих типов
            • Создание объектов
            • Создание сложных типов: Interfaces
            • Enums
            • Null Safe
            • Работа со строками и массивами
          • Ветвление кода и циклы
          • Фукнции и классы
            • Functions
            • Classes
          • Guards (проверка типов)
          • Generic-типы
          • Декораторы
          • Namespaces
          • Модули
          • Вспомогательные операторы
          • Дополнительные инструменты
          • Разные соглашения
        • Libraries
        • Frameworks
          • Web
            • React
              • Getting Started
              • Deploy
              • Packages
              • Security
              • Frameworks
                • Next.js
                • Remix
                • Gatsby
            • Vue.js
              • Nuxt.js
            • Angular
              • About
              • Основы фреймворка
                • Get Started
                • Angular CLI
                • Basic
                • Material Design Support
                • Components
                  • Introduction
                  • Lifecycle
                  • Create components
                  • Component Interaction
                  • Content Projection
                  • Dynamic components
                  • Angular Elements
                • Templates
                  • Text interpolation
                  • Template statements
                  • Pipes
                • Directives
                • Routing
                • Работа с сервисами
              • Packages
                • Списком
                • NgRx
                  • About
              • Cases
                • RxJs WebSockets
                • Errors
                • Code Styles And Best Practices
                • Примеры сайтов на Angular
            • SvelteJS
            • Others
              • jQuery
              • Meteor
              • AngularJS
              • Ext JS / Sencha
          • Mobile & Desktop
            • ReactNative
              • npx/react-native cli
            • Electron.js
          • State Managers
          • Rendering
          • i18n: Format.JS
        • Packet Managers
        • JS Runtime
          • Node.js
          • Deno
        • Other projects
      • CMS
      • Особенности WebStorm IDE
      • Dart/Flutter
        • About
        • Install
        • Packages & Plugins
        • Build & Run
        • Patterns
        • Dart
          • Intro
          • Variables
          • Functions
          • Operators
          • Control flow statements
          • Exceptions
          • Classes
          • Generics
          • Libraries and visibility
          • Asynchrony support
          • Generators
          • Isolates
          • Typedef
          • Packages
        • Flutter
          • Flutter CLI
          • pubspec.yaml
          • Widgets
          • Codelabs
          • Packages
          • Distribution
        • Dart & Flutter Playground
        • Кто использует Flutter
        • Papers & Tutorials
      • Сборщик JS/TS приложений
        • TODO: Webpack
        • TODO: Parcel
        • TODO: Rollup
      • Компиляторы
        • Babel
      • Testing
      • Learning
  • Others
    • Licenses
    • Фотостоки
    • Как оформить свой Github
    • Правила версионирования
    • Правила оформления коммитов
    • Стили именования переменных и классов
    • Language for IoT dev — TOIT
    • Online IDE
    • Документация по API по разным языкам в одном месте
    • Скиллы как специалиста
      • RoadMap для разных направлений
      • Задачи на программирование
      • Алгоритмы
      • Разработчик
      • Web-разработчик
      • DevOps
      • Бумажная ИБ
      • Компании ИБ
Powered by GitBook
On this page
  • Описание схемы базы данных
  • Базовый пример
  • Declarative vs. Imperative Forms¶
  • Организация кода для описания таблиц
  • Relationships
  • One-to-One
  • One-to-Many
  • Many-to-One
  • Many-to-Many
  • Конструирование запросов
  • Конструирование запросов к обычной таблице
  • Работа с relationships
  • Паттерн Provider -> Repository -> Database
  • database.py
  • repository.py
  • provider.py
  • Подсоединяемся к базе
  • Transactions
  • databases
  1. Programming Languages
  2. Backend
  3. Python
  4. Packages
  5. Databases

SQLAlchemy

PreviousPostgresNextАсинхронная обработка сообщений / работа с очередями

Last updated 12 months ago

Один из самых популярных пакетов для работы с базами данных — . Он позволяет конструировать запросы для различных баз данных. Рассмотрим основные практические моменты в работе с sqlalchemy.

— пакет для миграций

Описание схемы базы данных

Базовый пример

from sqlalchemy import Column, ForeignKey, String, Integer, Boolean, Table
from sqlalchemy.orm import declarative_base

from table_base import Base
from myrelationship import MyRelationship


Base = declarative_base()


class TableA(Base):
    __tablename__ = "table_a"

    key = Column(String(40), primary_key=True)
    value = Column(Integer, ForeighKey('table_b.id'))
    b = Column(Boolean)

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

Declarative Form with mapping (это новый подход, лучше использовать его!)

from sqlalchemy.orm import Mapper

class Parent(Base):
    __tablename__ = "parent_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    children: Mapped[List["Child"]] = relationship(back_populates="parent")


class Child(Base):
    __tablename__ = "child_table"

    id: Mapped[int] = mapped_column(primary_key=True)
    parent_id: Mapped[int] = mapped_column(ForeignKey("parent_table.id"))
    parent: Mapped["Parent"] = relationship(back_populates="children")

Declarative Form without mapping (это по классике):

class Parent(Base):
    __tablename__ = "parent_table"

    id = mapped_column(Integer, primary_key=True)
    children = relationship("Child", back_populates="parent")


class Child(Base):
    __tablename__ = "child_table"

    id = mapped_column(Integer, primary_key=True)
    parent_id = mapped_column(ForeignKey("parent_table.id"))
    parent = relationship("Parent", back_populates="children")

List and sets

По умолчанию, связи маппятся в List. Но можно сделать в Set:

class Parent(Base):
    __tablename__ = "parent_table"

    id = mapped_column(Integer, primary_key=True)
    children = relationship("Child", collection_class=set, ...)

Imperative Form:

У нас есть две таблицы, описанные декларативно. Добавляем связь императивно:

registry.map_imperatively(
    Parent,
    parent_table,
    properties={"children": relationship("Child", back_populates="parent")},
)

registry.map_imperatively(
    Child,
    child_table,
    properties={"parent": relationship("Parent", back_populates="children")},
)

Организация кода для описания таблиц

Один из возможных способов организации кода для описания схемы базы:

# table_base.py
from sqlalchemy.orm import declarative_base

Base = declarative_base()

# table_a.py
from sqlalchemy import Column, ForeignKey, String, Integer, Boolean, Table
from table_base import Base

class TableA(Base):
    __tablename__ = "table_a"

    value = Column(String(40), primary_key=True)

# table_b.py
from sqlalchemy import Column, ForeignKey, String, Integer, Boolean, Table
from table_base import Base

class TableB(Base):
    __tablename__ = "table_b"

    value = Column(String(40), primary_key=True)

# main.py
from table_a import TableA
from table_b import TableB
from table_base import Base

print(f'Base meta tables: {Base.metadata.tables}')

Relationships

One-to-One

На базовом уровне это выглядит следующим образом. То есть, мы отключаем поддержку коллекций и тем самым добиваемся One-to-One отношения. Это нужно, когда у родителя может быть только один ребенок, а у ребенка — один родитель.

class Parent(Base):
    __tablename__ = "parent_table"
    id = Column(Integer, primary_key=True)

    # previously one-to-many Parent.children is now
    # one-to-one Parent.child
    child = relationship("Child", back_populates="parent", uselist=False)


class Child(Base):
    __tablename__ = "child_table"
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("parent_table.id"))

    # many-to-one side remains, see tip below
    parent = relationship("Parent", back_populates="child")

One-to-Many

На базовом уровне это выглядит следующим образом

# base.py
from sqlalchemy.orm import declarative_base
Base = declarative_base()

# parent.py
from sqlalchemy import Column, Integer
from sqlalchemy.orm import relationship

from base import Base


class Parent(Base):    
    __tablename__  = "parent_table"
    id = Column(Integer, primary_key=True)
    children = relationship("Child")
    
# child.py
from sqlalchemy import Column, Integer, ForeignKey

from base import Base


class Child(Base):
    __tablename__  = "child_table"
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("parent_table.id"))
    
# main.py
from sqlalchemy import select, insert

from parent import Parent
from child import Child


print(select(Parent))
print(select(Child))

Для двунаправленной связи, чтобы Child видел Parent целиком, а не только id (далее не надо будет делать отдельный запрос на уровне кода), изменим Child и Parent следующим образом:

# parent.py
class Parent(Base):    
    __tablename__  = "parent_table"
    id = Column(Integer, primary_key=True)
    children = relationship("Child", back_populates="parent")

# child.py
class Child(Base):
    __tablename__  = "child_table"
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("parent_table.id"))
    parent = relationship("Parent", back_populates="children")

Many-to-One

На базовом уровне это выглядит следующим образом

# base.py
from sqlalchemy.orm import declarative_base
Base = declarative_base()

# parent.py
from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship

from base import Base

class Parent(Base):
    __tablename__ = "parent_table"
    id = Column(Integer, primary_key=True)
    child_id = Column(Integer, ForeignKey("child_table.id"))
    child = relationship("Child")

# child.py
from sqlalchemy import Column, Integer, ForeignKey

from base import Base

class Child(Base):
    __tablename__  = "child_table"
    id = Column(Integer, primary_key=True)


# main.py
from sqlalchemy import select, insert

from parent import Parent
from child import Child


print(select(Parent))
print(select(Child))

Для двунаправленной связи, чтобы из Child можно было получить всех родителей, поменяем Parent и Child следующим образом

class Parent(Base):
    __tablename__ = "parent_table"
    id = Column(Integer, primary_key=True)
    child_id = Column(Integer, ForeignKey("child_table.id"))
    child = relationship("Child", back_populates="parents")
    
class Child(Base):
    __tablename__  = "child_table"
    id = Column(Integer, primary_key=True)
    parents = relationship("Parent", back_populates="child")

Many-to-Many

На базовом уровне это выглядит следующим образом.

association_table = Table(
    "association_table",
    Base.metadata,
    Column("left_id", ForeignKey("left_table.id"), primary_key=True),
    Column("right_id", ForeignKey("right_table.id"), primary_key=True),
)


class Parent(Base):
    __tablename__ = "left_table"
    id = Column(Integer, primary_key=True)
    children = relationship(
        "Child", secondary=association_table, back_populates="parents"
    )


class Child(Base):
    __tablename__ = "right_table"
    id = Column(Integer, primary_key=True)
    parents = relationship(
        "Parent", secondary=association_table, back_populates="children"
    )

Мы создаем ассоциативную таблицу, которая хранит все уникальные пары ключей из обоих таблиц и подключаем ее через свойство secondary. Через свойство back_populates настраиваем связь.

Конструирование запросов

Конструирование запросов к обычной таблице

from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer
from sqlalchemy import select, insert, update

Base = declarative_base()

class MyTable(Base):
   __tablename__ = "my_table"
   id = Column(Integer, primary_key=True)  # default: auto increment
   value = Column(String)
   
# INSERT
query = (
   insert(MyTable).
   values(
      value="some"
   ).
   returning(MyTable.id, MyTable.value)
)
print(query)

# SELECT
print(select(MyTable))
print(select(MyTable).where(MyTable.id == 1))

# UPDATE
from pydantic import BaseModel
class Value(BaseModel):
   value: str
   
value = Value(**{"value": "some"})
query = (
   update(MyTable).
   where(MyTable.id == 1).
   values(value.dict())   
)
# Такое сработает только если все ключи в PyDantic объекте совпадают с именами колонок в таблице
# Иначе прописываем все поля вручную

# DELETE
delete(MyTable).where(MyTable.id == id)

Работа с relationships

class First(Base):
    __tablename__  = "first_table"
    id = Column(Integer, primary_key=True)
    seconds = relationship("Second", secondary=association_table, back_populates="firsts")
    
select(First.seconds)
# И мы получаем достаточно сложный запрос, который вернет нам эти данные

First.seconds.remove(somechild)
# И это автоматически удалит запись и из secondary. Самим ходить и удалять допом ничего не надо

Паттерн Provider -> Repository -> Database

Есть популярный паттерн организации кода при работе с базой (из джавы, на сколько его правильно применять в Python — хз, но так понятнее что происходит). Суть в отделении бизнес-логики (это Provider), CRUD-операций (это Repository) и работы с базой (это Database).

Пример:

database.py

import databases
import sqlalchemy
import logging
from pydantic import BaseSettings


class DatabaseWrapper(object):
    database: databases.Database
    logger: logging.Logger

    def __init__(self, config: BaseSettings) -> None:
        self.logger = logging.getLogger(config.LOGGER_NAME)
        self.database = databases.Database(config.DATABASE_URL)

        self._engine = sqlalchemy.create_engine(
            config.DATABASE_URL,
        )
        
    async def connect(self):
        await self.database.connect()
        self.logger.debug(f'Connect to database')

    async def disconnect(self):
        await self.database.disconnect()
        self.logger.debug(f'Disconnect from database')

repository.py

class CompanyRepository(object):
    def __init__(self, database: DatabaseWrapper) -> None:
        self.database = database
        self.logger = database.logger

    async def create(self, company_info: CompanyInfo, status: Status) -> Company:
        
        query = (
            insert(CompanyTable).
            values(
                status_id=status.id, 
                link=company_info.link, 
                name=company_info.name
            ).
            returning(CompanyTable.id, CompanyTable.link, CompanyTable.name, CompanyTable.status_id)
        )
        company_id = await self.database.execute(query)
        created_company = await self.read(company_id)

        return created_company

provider.py

class CompanyProvider(object):
   def __init__(self, database: DatabaseWrapper):
      self.company_repository = CompanyRepository(database)
      
   async def new_company(self, company_info: CompanyInfo) -> Company:
      status_new = await self.status_repository.create()
      created_company = await self.company_repository.create(company_info, status_new)
      
      return created_company

Подсоединяемся к базе

Transactions

with Session(engine) as session:
   user = TableUser(username='test')
   session.add(user)

   phones = [TablePhone(user=user, number='+31111111111')]
   session.add_all(phones)

   session.commit()

   return user.id

databases

Выполнение запросов к базе делаем через пакет databases. Только схему базы в бд создаем через sqlalchemy (из объекта Base).

import databases
import sqlalchemy

from base import Base  # from sqlalchemy.orm import declarative_base
                       # Base = declarative_base()

database = databases.Database(DATABASE_URL)
engine = sqlalchemy.create_engine(DATABASE_URL)
Base.metadata.create_all(engine)

database.connect()
# ...
database.disconnect()

Declarative vs. Imperative Forms

Если нам надо добавить в ассоциацию доп поля, или мы хотим чтобы все было в одном стиле, можем создать обычную таблицу как Child и Parent:

Выполнение делаем через SQLAlchemy используя транзакции (Session):

sqlalchemy
alembic
¶
https://docs.sqlalchemy.org/en/14/orm/basic_relationships.html#association-object
https://habr.com/ru/articles/597999/