Я пытаюсь создать набор таблиц, используя SQLAlchemy 2.0.
import logging
import logging.handlers
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(name)-5s] [%(levelname)-3s] %(message)s'
)
from typing import List, Dict
# from DAL.database import Report, Database
import util.utility as util
import sqlalchemy
from sqlalchemy import MetaData, DateTime, func, exc
from sqlalchemy.engine import Engine
from sqlalchemy.orm import relationship, sessionmaker, Mapped, DeclarativeBase, mapped_column
from datetime import datetime
config: Dict = util.read_config("../static/configurations/custom.yaml")
class Base(DeclarativeBase):
pass
class Attribute_Details(Base):
"""
"""
__tablename__ = "attribute_details"
id: Mapped[int] = mapped_column(primary_key=True)
description: Mapped[str] = mapped_column()
opened: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
closed: Mapped[datetime] = mapped_column()
report_attr: Mapped["Report_Attributes"] = relationship(back_populates = "details")
class Database:
"""
Abstraction layer for the SQLAlchemy db interface
"""
meta: MetaData
engine: Engine
session_maker: sessionmaker
__connected: bool = False
tables: List[Base] = [Attribute_Details]
def __init__(self, con_str: str):
self.logger = logging.getLogger(Database.__name__)
self.logger.info("Connecting to DB: {}".format(con_str))
self.db = sqlalchemy.create_engine(con_str, echo=False)
def connect(self) -> bool:
"""
Establish connection to the database
"""
try:
self.engine = self.db.connect()
self.session_maker = sessionmaker(bind=self.engine)
self.meta = sqlalchemy.MetaData()
return True
except exc.SQLAlchemyError as e:
print(str(e))
return False
def create_tables(self):
"""
Create the corresponding tables for the Report template
"""
for table in self.tables:
if not self.engine.dialect.has_table(self.engine, table.__tablename__):
table_obj = [table.__table__]
Base.metadata.create_all(self.engine, tables=table_obj)
# CreateTable(table_obj).compile(dialect=postgresql.dialect())
self.logger.info("Created DB Table {}".format(table.__tablename__))
else:
self.logger.info("DB Table {} already exists".format(table.__tablename__))
db = Database(config['db_con_test'])
db.connect()
db.create_tables()
Хотя он сообщает «Создана таблица БД атрибут_детали», таблица не создается в базе данных. Я попробовал вариант с Base.metadata.create_all(), а также CreateTable(). Я не могу обнаружить проблему, поскольку создание таблиц с помощью нового декларативного сопоставления SQL2.0 не очень хорошо объяснено... по крайней мере, для меня.
Обновил код до полного MVE (кроме того, что вам нужна база данных postgresql), но таблица по-прежнему не создается. Есть ли способ получить дополнительную информацию о причине, по которой Алхимия не создала таблицу?
Ваш self.engine не является объектом Engine, это объект Connection. Очевидно, когда .create_all() передается соединение, оно предполагает, что вы приняли на себя ответственность за обработку транзакций, поэтому он выдает оператор CREATE TABLE для этого соединения, но не фиксирует (потому что это ваша работа). Я бы посоветовал вам не использовать имена self.db для вашего объекта Engine и self.engine для вашего объекта Connection — это слишком запутанно.
«Есть ли способ получить больше информации о причине, по которой Алхимия не создала стол?» — Использование echo=True или echo = "debug" при вызове create_engine() часто бывает полезным.
@GordThompson, ты хочешь опубликовать ответ? Ваше мнение относительно перепутанного соединения и двигателя было правильным.






Типичное использование — вызов .create_all() с объектом Engine.
from sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
class Base(DeclarativeBase):
pass
class Thing(Base):
__tablename__ = "thing"
id: Mapped[int] = mapped_column(primary_key=True)
description: Mapped[str]
engine = create_engine("sqlite://", echo=True)
Base.metadata.create_all(engine)
"""
CREATE TABLE thing (
id INTEGER NOT NULL,
description VARCHAR NOT NULL,
PRIMARY KEY (id)
)
2024-06-12 06:37:19,592 INFO sqlalchemy.engine.Engine [no key 0.00018s] ()
2024-06-12 06:37:19,592 INFO sqlalchemy.engine.Engine COMMIT
Process finished with exit code 0
"""
Очевидно, когда .create_all() передается соединение, оно предполагает, что вы приняли на себя ответственность за обработку транзакций, поэтому он выдает оператор CREATE TABLE для этого соединения, но не фиксирует (потому что это ваша работа).
engine = create_engine("sqlite://", echo=True)
conn = engine.connect()
Base.metadata.create_all(conn)
"""
CREATE TABLE thing (
id INTEGER NOT NULL,
description VARCHAR NOT NULL,
PRIMARY KEY (id)
)
2024-06-12 06:42:01,819 INFO sqlalchemy.engine.Engine [no key 0.00024s] ()
Process finished with exit code 0
"""
Однако если мы используем менеджер контекста (как рекомендуется для SQLAlchemy 2+), то это также может привести к выполнению фиксации. .create_all() не выполняет коммит, но это делает контекстный менеджер.
engine = create_engine("sqlite://", echo=True)
with engine.begin() as conn: # "begin once" pattern
Base.metadata.create_all(conn)
"""
CREATE TABLE thing (
id INTEGER NOT NULL,
description VARCHAR NOT NULL,
PRIMARY KEY (id)
)
2024-06-12 06:46:09,601 INFO sqlalchemy.engine.Engine [no key 0.00027s] ()
2024-06-12 06:46:09,601 INFO sqlalchemy.engine.Engine COMMIT
Process finished with exit code 0
"""
Пожалуйста, отредактируйте вопрос, чтобы предоставить минимально воспроизводимый пример. Например,
connectиcreate_tables— это методы класса, но в вашем вопросе их нет в классе. После внесения изменений, необходимых для запуска кода, я не смог воспроизвести проблему.