SqlAlchemy结合dataclass与声明式mixin报AttributeError无法赋值问题咨询
问题原因
错误来自两方面冲突:
- 你在
OwnedThingmixin中同时定义了owner_id/owner类属性,又用@declared_attr装饰了同名方法,SQLAlchemy的@declared_attr会生成描述符类属性,和dataclass自动生成的属性赋值逻辑冲突,导致实例化时无法给属性赋值。 - 你当前的
Owner类没有定义ORM映射需要的主键字段,也没有关联到SQLAlchemy的声明基类,外键关联owner.id本身也无法生效。
修复方案
调整代码逻辑,避免属性重复定义,同时对齐SQLAlchemy ORM的映射规则即可,修复后可运行代码如下:
from dataclasses import dataclass, field from abc import ABC from sqlalchemy.orm import ( declarative_base, declarative_mixin, declared_attr, relationship ) from sqlalchemy import Column, ForeignKey, Integer, String # 首先定义SQLAlchemy的声明基类 Base = declarative_base() # Owner类改为标准ORM映射类,补充主键id @dataclass class Owner(Base): __tablename__ = "owner" id: int = Column(Integer, primary_key=True, autoincrement=True) name: str = Column(String, default="") @declarative_mixin @dataclass class OwnedThing(ABC): # 标记为init=False让dataclass不在初始化方法中处理这两个字段,由ORM管理 owner_id: int = field(init=False, default=None) owner: Owner = field(init=False, default=None) @declared_attr def owner_id(cls): return Column('owner_id', ForeignKey('owner.id')) @declared_attr def owner(cls): return relationship(Owner) # 子类需要同时继承声明基类Base和mixin @dataclass class Thing1(OwnedThing, Base): __tablename__ = "thing1" id: int = Column(Integer, primary_key=True, autoincrement=True) name: str = Column(String, default="") # 测试逻辑 owner = Owner(name="foo") thing = Thing1(name="bar", owner=owner) print(thing.owner.name)
关键修改点
- 移除了mixin中与
@declared_attr同名的直接属性赋值,避免描述符冲突 - 给ORM管理的
owner_id/owner字段用field(init=False)标记,让dataclass不要尝试在初始化方法中处理这两个属性 - 补充了SQLAlchemy映射需要的声明基类、表名、主键字段,完善ORM映射逻辑
- 子类同时继承声明基类和mixin,触发SQLAlchemy的映射逻辑,不再报非映射类的警告
内容的提问来源于stack exchange,提问作者Stephen Howard
相关产品推荐
相关产品推荐

