Flask-SQLAlchemy中declared_attr定义__tablename__未正确切换目标数据表的问题咨询
嘿,我来帮你拆解这个问题!你遇到的情况其实是Flask-SQLAlchemy默认的继承策略在起作用,咱们一步步理清楚:
问题根源
你当前的代码里,User是一个普通的Flask-SQLAlchemy模型类,当User_us继承它时,SQLAlchemy默认会启用**单表继承(Single Table Inheritance)**模式。这种模式下,父类和子类会共用同一张数据库表(也就是父类的user表),子类只是作为父类的"特殊类型"存在——哪怕你用declared_attr把User_us的__tablename__设成了user_us,实际关联的表对象还是父类的user表,这就是为什么User_us.__table__.name输出的是user。
而你想要的是每个类对应独立的数据表,也就是让子类基于父类的结构创建自己的表,这时候需要把父类标记为抽象基类。
解决方法
只需要在父类User里添加__abstract__ = True,告诉Flask-SQLAlchemy这个类只是用来继承的模板,不会生成自己的表,子类会各自创建独立的表:
from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class User(db.Model): __abstract__ = True # 关键:标记为抽象基类 @declared_attr def __tablename__(cls) -> str: return str(cls.__name__.lower()) id = db.Column(db.Integer, primary_key=True) class User_us(User): pass # 现在测试输出就符合预期了 print(f'Test state: {User_us.__tablename__} {(User_us.__table__.name)}')
运行这段代码后,输出会变成你预期的:
Test state: user_us user_us
额外说明
你会发现User_us.__tablename__原本就是user_us,这说明declared_attr是生效的——问题根本不是这个装饰器的功能失效,而是默认的继承策略让子类复用了父类的表对象。标记抽象基类后,子类会完全基于父类的字段定义,生成自己的表结构和表对象,自然就会对应到user_us表了。
备注:内容来源于stack exchange,提问作者William

