SQLAlchemy 不创建表

3 python sqlalchemy

我正在尝试像在教程中一样设置数据库,但是当我尝试添加一个表时,我遇到了一个表不存在的编程错误 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()
Run Code Online (Sandbox Code Playgroud)

要初始化数据库(创建表),我只需运行该文件。创建测试用户时出错。

这是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)
Run Code Online (Sandbox Code Playgroud)

我试过:

  • 添加用户之前提交(之后create_all
  • 从数据库中删除现有表(尽管该表似乎永远不会被提交)
  • from models import User而不是import models(之前create_all

对不起,如果有这么多类似的问题,我保证我会寻找答案,但我确信我没有犯过(或至少是我看到的那些)的愚蠢错误。

我正在使用 MariaDB。

对不起,很长的帖子,非常感谢提前。

Sup*_*oot 7

Basedatabase.py是不一样的Base被导入models.py

一个简单的测试是print('creating Base')Base = declarative_base()语句上方放置一个函数调用,您会看到它被创建了两次。

Python 调用正在执行的模块,'__main__'您知道它if __name__ == '__main__'在模块底部有条件。所以第一个Base创建的是__main__.Base. 然后, in models.pyfrom database import Base导致database模块再次被解析,database.Base在命名空间中创建,BaseUser继承自。然后回到database.pyBase.metadata.create_all(bind=engine)调用正在使用__main__.Base其中没有表的元数据,因此不会创建任何内容。

不要在创建Base实例的模块之外执行。创建一个名为另一模块main.py(或其他),以及移动你的init_db()存在和导入功能Basedb_sessionenginedatabase.pymain.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()
Run Code Online (Sandbox Code Playgroud)


小智 6

  • 声明基类一次(对于每个数据库)并将其导入到定义表类的所有模块(继承自 Base)
  • 为了让 Base(元类)扫描并找出从它继承的所有类,我们需要将定义此类表类(继承自 Base)的所有模块导入到我们调用 Metadata.create_all(engine) 的模块中。