SQLAlchemy не создает таблицы - PullRequest
0 голосов
/ 09 января 2019

Я пытаюсь настроить базу данных, как в учебнике, но я получаю программную ошибку, что таблица не существует, когда я пытаюсь добавить User

Это файл с ошибками (database.py):

from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base


engine = create_engine(
    "mysql+pymysql://testuser:testpassword@localhost/test?charset=utf8",
    connect_args = {
        "port": 3306
    },
    echo="debug",
    echo_pool=True
)

db_session = scoped_session(
    sessionmaker(
        bind=engine,
        autocommit=False,
        autoflush=False
    )
)

Base = declarative_base()

def init_db():
    import models
    Base.metadata.create_all(bind=engine)

    from models import User
    db_session.add(
        User(username="testuser", password_hash=b"", password_salt=b"", balance=1)
    )
    db_session.commit()

    print("Initialized the db")


if __name__ == "__main__":
    init_db()

Для инициализации базы данных (создания таблиц) я просто запускаю файл. Ошибка при создании тестового пользователя.

Вот models.py:

from sqlalchemy import Column, Integer, Numeric, Binary, String
from sqlalchemy.orm import relationship

from database import Base


class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True)

    username = Column(String(16), unique=True)
    password_hash = Column(Binary(32))
    password_salt = Column(Binary(32))

    balance = Column(Numeric(precision=65, scale=8))

    def __repr__(self):
        return "<User(balance={})>".format(balance)

Я пытался:

  • Фиксация перед добавлением пользователей (после create_all)
  • Удалить существующие таблицы из базы данных (хотя кажется, что таблица никогда не будет зафиксирована)
  • from models import User вместо import models (до create_all)

Извините, если есть так много схожих вопросов, я обещаю, что собирал ответы, но это всегда глупые ошибки, которые я допускал, чтобы не совершать (или, по крайней мере, те, которые я видел).

Я использую MariaDB.

Извините за длинный пост, большое спасибо заранее.

Ответы [ 2 ]

0 голосов
/ 30 июля 2019
  • Объявите Базовый класс один раз (для каждой базы данных) и импортируйте его во все модули, которые определяют классы таблиц (унаследованные от Base)
  • Чтобы Base (метакласс) сканировал и обнаруживал все классы, которые унаследованы от него, нам нужно импортировать все модули, где такие классы таблиц (унаследованные от Base), определены в модуль, где мы вызываем Metadata.create_all (engine ).
0 голосов
/ 10 января 2019

Base в database.py - это не то же самое Base, которое импортируется в models.py.

Простой тест - поместить вызов функции print('creating Base') чуть выше оператора Base = declarative_base(), и вы увидите, что он создается дважды.

Python вызывает выполняемый модуль '__main__', который вы знаете, поскольку у вас есть условное выражение if __name__ == '__main__' внизу вашего модуля. Итак, первый Base, который был создан, это __main__.Base. Затем в models.py, from database import Base вызывает повторный анализ модуля database, создавая database.Base в пространстве имен, и это - Base, от которого наследуется User. Затем в database.py вызов Base.metadata.create_all(bind=engine) использует метаданные из __main__.Base, в которых нет таблиц и поэтому ничего не создает.

Не выполнять из модуля, который создает экземпляр Base. Создайте другой модуль с именем main.py (или любым другим) и переместите туда свою функцию init_db() и импортируйте Base, db_session и engine из database.py в main.py. Таким образом, вы всегда используете один и тот же экземпляр Base. Это пример main.py:

from database import Base, db_session, engine
from models import User


def init_db():

    Base.metadata.create_all(bind=engine)

    db_session.add(
        User(username="testuser", password_hash=b"", password_salt=b"", balance=1)
    )
    db_session.commit()

    print("Initialized the db")


if __name__ == "__main__":
    init_db()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...