Повышение безопасности, когда отношение SQLAlchemy добавляет условия, ссылающиеся на еще не существующие таблицы.Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Повышение безопасности, когда отношение SQLAlchemy добавляет условия, ссылающиеся на еще не существующие таблицы.

Сообщение Anonymous »

У меня есть ситуация, когда я хочу настроить отношения между таблицами, сопоставленными с уровнем ORM SQLAlchemy, где эти отношения имеют дополнительный ключ соединения. Насколько я знаю, настройка вручную требует встраивания строк, которые оцениваются; Я пытаюсь выяснить, в какой степени этого можно избежать или по крайней мере проверить заранее (в идеале с помощью Pyright или MyPy, до выполнения).
Возьмите следующая схема, в которую еще не добавлен дополнительный ключ соединения:

Код: Выделить всё

from typing import List
from uuid import UUID
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
from sqlalchemy.schema import ForeignKey
from sqlalchemy.types import Uuid
import sqlalchemy as sa

class Base(DeclarativeBase): pass

class User(Base):
__tablename__ = 'user'
id: Mapped[UUID] = mapped_column(Uuid(), primary_key=True)
tenant_id: Mapped[UUID] = mapped_column(Uuid())
actions: Mapped[List["Action"]] = relationship("Action", back_populates="user", foreign_keys="Action.user_id")

class Action(Base):
__tablename__ = 'action'
id: Mapped[UUID] = mapped_column(Uuid(), primary_key=True)
tenant_id: Mapped[UUID] = mapped_column(Uuid())
user_id: Mapped[UUID] = mapped_column(Uuid(), ForeignKey("user.id"))
user: Mapped["User"] = relationship("User", back_populates="actions", foreign_keys=[user_id])

Base.metadata.create_all(sa.create_engine('sqlite://', echo=True))
Это достаточно просто, если мы не пытаемся добавить защиту ремнями и подтяжками от оценок отношений, связывающих между арендаторами. Как только мы это сделаем, объявления отношений должны быть строками каждый раз, когда необходимо ссылаться на еще необъявленный класс:

Код: Выделить всё

class User(Base):
__tablename__ = "user"
id: Mapped[UUID] = mapped_column(Uuid(), primary_key=True)
tenant_id: Mapped[UUID] = mapped_column(Uuid())
actions: Mapped["Action"] = relationship("Action",
back_populates="user",
foreign_keys="Action.user_id",
primaryjoin="and_(tenant_id == Action.tenant_id, id == Action.user_id)",
)

class Action(Base):
__tablename__ = "action"
id: Mapped[UUID] = mapped_column(Uuid(), primary_key=True)
tenant_id: Mapped[UUID] = mapped_column(Uuid())
user_id: Mapped[UUID] = mapped_column(Uuid(), ForeignKey("user.id"))
user: Mapped["User"] = relationship("User",
back_populates="actions",
foreign_keys=[user_id],
primaryjoin=sa.and_(tenant_id == User.tenant_id, user_id == User.id),
)
Вышеупомянутое работает, но с этим Primaryjoin="and_(tenant_id == Action.tenant_id, id == Action.user_id)" строка, в которой тяжелая работа выполняется в контексте, непрозрачном для статического анализа, является неудачной.
Если бы мы могли предоставить код, который оценивается после определения всех типов, но до SQLAlchemy начинает самоанализ, который позволит использовать вспомогательную функцию для генерации отношений. Это по-прежнему не подходит для статической проверки, но это значительно лучше, чем ничего. Однако я не знаю, произойдет ли соответствующий самоанализ (если отношения должны существовать при вызове __init_subclass__), любая попытка добавить их позже будет слишком поздно ).
SQLAlchemy имеет ряд возможностей, с которыми я сразу не знаком, поэтому надеюсь, что есть вариант, о котором я здесь не думаю.

Подробнее здесь: https://stackoverflow.com/questions/791 ... efer-to-ta
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»