Вопрос или проблема
Я пытаюсь создать внешний ключ к таблице, которая управляется Django ORM, однако SQLA, похоже, не любит это.
class SomeSAModel(DeclarativeBase):
user_id: Mapped[int] = mapped_column(
sa.ForeignKey("users_customuser.id") # это ссылка на таблицу Django
)
И это ошибка, которую я получаю, когда запускаю alembic revision --autogenerate
File "/home/dev/Desktop/t5hob/Backend/alembic/env.py", line 137, in run_migrations_online
context.run_migrations()
File "<string>", line 8, in run_migrations
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/runtime/environment.py", line 946, in run_migrations
self.get_context().run_migrations(**kw)
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/runtime/migration.py", line 616, in run_migrations
for step in self._migrations_fn(heads, self):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/command.py", line 212, in retrieve_migrations
revision_context.run_autogenerate(rev, context)
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/autogenerate/api.py", line 570, in run_autogenerate
self._run_environment(rev, migration_context, True)
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/autogenerate/api.py", line 617, in _run_environment
compare._populate_migration_script(
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/autogenerate/compare.py", line 65, in _populate_migration_script
_produce_net_changes(autogen_context, upgrade_ops)
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/autogenerate/compare.py", line 98, in _produce_net_changes
comparators.dispatch("schema", autogen_context.dialect.name)(
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/util/langhelpers.py", line 310, in go
fn(*arg, **kw)
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/autogenerate/compare.py", line 134, in _autogen_for_tables
[(table.schema, table.name) for table in autogen_context.sorted_tables]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 1141, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/alembic/autogenerate/api.py", line 482, in sorted_tables
result.extend(m.sorted_tables)
^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/sql/schema.py", line 5626, in sorted_tables
return ddl.sort_tables(
^^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/sql/ddl.py", line 1252, in sort_tables
for (t, fkcs) in sort_tables_and_constraints(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/sql/ddl.py", line 1328, in sort_tables_and_constraints
dependent_on = fkc.referred_table
^^^^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/sql/schema.py", line 4753, in referred_table
return self.elements[0].column.table
^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/util/langhelpers.py", line 1141, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/sql/schema.py", line 3170, in column
return self._resolve_column()
^^^^^^^^^^^^^^^^^^^^^^
File "/home/dev/Desktop/t5hob/Backend/.venv/lib/python3.12/site-packages/sqlalchemy/sql/schema.py", line 3193, in _resolve_column
raise exc.NoReferencedTableError(
sqlalchemy.exc.NoReferencedTableError: Внешний ключ, связанный со столбцом 'incidents__incident.ack_by', не может найти таблицу 'users_customuser', с которой нужно сгенерировать внешний ключ к целевому столбцу 'id'
Ответ или решение
Чтобы создать внешний ключ (Foreign Key) для таблицы, управляемой не SQLAlchemy ORM, а Django ORM, необходимо учесть несколько важных аспектов. При этом нужно понимать, что SQLAlchemy может не распознавать некоторые таблицы, если они созданы или управляются другими системами, такими как Django. Ниже представлен подробный алгоритм действий, который поможет решить описанную вами проблему.
Шаг 1: Поиск решения проблемы с миграцией
Вы сталкиваетесь с ошибкой NoReferencedTableError
, что указывает на то, что SQLAlchemy не может найти таблицу users_customuser
, к которой вы пытаетесь создать внешний ключ. Это может произойти, если таблица создана, но SQLAlchemy не знает о ней. Чтобы решить эту проблему, можно использовать некоторые обходные пути.
Шаг 2: Объявление таблицы в SQLAlchemy
Для начала вам нужно вручную определить метаданные таблицы users_customuser
в SQLAlchemy. Это позволяет SQLAlchemy узнать о ее существовании и правильно работать с ней. Вы можете сделать это следующим образом:
from sqlalchemy import Table, Column, Integer, MetaData
metadata = MetaData()
users_custom_user = Table(
'users_customuser', metadata,
Column('id', Integer, primary_key=True),
# Добавьте другие поля, если необходимо
)
Шаг 3: Определение модели с внешним ключом
Теперь, когда у вас есть определение таблицы, вы можете настроить модель SomeSAModel
с использованием этого внешнего ключа. Убедитесь, что вы ссылаетесь на определение таблицы, которое вы создали на предыдущем шаге.
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.ext.declarative import declarative_base
DeclarativeBase = declarative_base()
class SomeSAModel(DeclarativeBase):
__tablename__ = 'incidents__incident'
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int] = mapped_column(sa.ForeignKey('users_customuser.id'))
Шаг 4: Применение миграции с Alembic
После того, как вы скорректировали ваши определения, попробуйте повторно выполнить команду для миграции:
alembic revision --autogenerate
Шаг 5: Убедитесь в наличии таблицы
Прежде чем выполнять миграции, убедитесь, что таблица users_customuser
действительно существует в вашей базе данных, иначе вы всё равно столкнётесь с ошибками.
Заключение
В результате, правильное управление зависимостями таблиц между SQLAlchemy и Django ORM требует ручного определения таблиц, чтобы ORM могла правильно работать с миграциями и настройками базы данных. Если вы следуете описанным шагам, ваша проблема с созданием внешнего ключа должна быть успешно решена.
Важно понимать, что такой подход к интеграции требует внимательного планирования структуры базы данных и, возможно, использования дополнительных инструментов для синхронизации миграций между двумя ORM.