Как создавать новые таблицы без определенных классов в SQLAlchemy 1.2.7 - PullRequest
0 голосов
/ 28 апреля 2018

Я использую декларативный API SQLAlchemy для построения своих моделей и таблиц для своего приложения.

Однако я не могу использовать команду Base.metadata.create_all(engine) для создания новой таблицы в моей базе данных из-за ошибки NoReferencedTableError: Foreign key associated with column 'org_prediction.company_id' could not find table 'organization' with which to generate a foreign key to target column 'id'

Причина, по которой это происходит, заключается в том, что класс Organization, на который я пытаюсь ссылаться для ForeignKey, не существует в моем файле models.py. Итак, когда я вызываю Base.metadata.create_all(engine), SQLAlchemy задыхается, потому что в организации нет класса Organization ...

Я попытался отразить мою базу данных, которая будет возвращать таблицу для Organization, которая существует, но в моем файле models.py для нее не написан соответствующий класс. Но когда я отражаю таблицы БД и пытаюсь создать свой новый зависимый класс поверх Organisation, я получаю сообщение об ошибке: InvalidRequestError: Table 'user' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object., которое вызвано тем, что отраженные MetaData и мой models.py класс для пользователя перекрываются, а SQLAlchemy isn не уверен, что делать.

Но где я могу применить extended_existing = True? У меня нет объектов Table для передачи этого параметра. Как я могу создать свою FK-зависимую таблицу, если моя FK-зависимая таблица не существует в моем файле models.py? Или как я могу отразить мои существующие таблицы, но добавить или обновить только те классы, которые еще не существуют в базе данных?

models.py

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(50))

class OrgPrediction(Base):
    __tablename__ = 'org_prediction'
    id = Column(Integer, primary_key=True)
    company_id = Column(String(255), ForeignKey('organization.id'), nullable=True)
    prediction = Column(String(255)
Base.metadata.create_all(engine)

NoReferencedTableError: внешнему ключу, связанному со столбцом 'org_prediction.company_id', не удалось найти таблицу 'organization', с которой можно сгенерировать внешний ключ для целевого столбца 'id'

MYSQL:

mysql> desc organization;
+-----------------------+------------+------+-----+---------+-------+
| Field                 | Type       | Null | Key | Default | Extra |
+-----------------------+------------+------+-----+---------+-------+
| id                 | bigint(20) | YES  | MUL | NULL    |       |


mysql> show tables;
+-------------------------+
| Tables_in_database |
+-------------------------+
| organization            |
| user                    |
| user_email              |

В случае Reflection файл models.py:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine

Base = automap_base()
Base.prepare(engine, reflect=True)

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(50))

class OrgPrediction(Base):
    __tablename__ = 'org_prediction'
    id = Column(Integer, primary_key=True)
    company_id = Column(String(255), ForeignKey('organization.id'), nullable=True)

Base.metadata.create_all(engine)

InvalidRequestError: Таблица 'user' уже определена для этого экземпляра MetaData. Укажите значение extension_existing = True, чтобы переопределить параметры и столбцы для существующего объекта Table.

1 Ответ

0 голосов
/ 16 мая 2018

Существует способ сделать это, и он предполагает использование функциональности Base.metadata.reflect (only = ['table_name']) до добавления таблицы зависимостей Foreign-Key. Итоговый код, который я тестировал:

Base = declarative_base()
class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(50))

#see what tables exist in metadata right now
In [85]: Base.metadata.sorted_tables
Out[85]: [Table('user', MetaData(bind=None), Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('username', String(length=50), table=<user>), schema=None)]

# this will add the organization table/class to the Base's Metadata. This also needs to happen before the Foreign Key reference in OrgPrediction class.
Base.metadata.reflect(bind=engine, only=['organization'])

# now this class' foreign key will reference organization.id which exists in Base metadata.
class OrgPrediction(Base):
    __tablename__ = 'org_prediction'
    id = Column(Integer, primary_key=True)
    company_id = Column(String(255), ForeignKey('organization.id'), nullable=True)
    prediction = Column(String(255))

# this should pass because the foreign key constraint is met.
Base.metadata.create_all(engine)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...