SQLAlchemy中的多对一关系
这是一个初学者的问题。
我有一个叫做 mtypes 的目录:
mtype_id name
1 'mtype1'
2 'mtype2'
[etc]
还有一个叫做 Objects 的目录,每个对象都必须有一个对应的 mtype:
obj_id mtype_id name
1 1 'obj1'
2 1 'obj2'
3 2 'obj3'
[etc]
我想在 SQLAlchemy 中通过创建以下模式来实现这个:
mtypes_table = Table('mtypes', metadata,
Column('mtype_id', Integer, primary_key=True),
Column('name', String(50), nullable=False, unique=True),
)
objs_table = Table('objects', metadata,
Column('obj_id', Integer, primary_key=True),
Column('mtype_id', None, ForeignKey('mtypes.mtype_id')),
Column('name', String(50), nullable=False, unique=True),
)
mapper(MType, mtypes_table)
mapper(MyObject, objs_table,
properties={'mtype':Relationship(MType, backref='objs', cascade="all, delete-orphan")}
)
当我尝试添加一个简单的元素,比如:
mtype1 = MType('mtype1')
obj1 = MyObject('obj1')
obj1.mtype=mtype1
session.add(obj1)
我遇到了这个错误:
AttributeError: 'NoneType' object has no attribute 'cascade_iterator'
有什么想法吗?
2 个回答
我能运行你上面展示的代码,所以我猜问题在你为了这个问题简化代码时就解决了,对吗?
你没有提供错误追踪信息,所以我只能给一些一般性的建议。
在SQLAlchemy(至少在0.5.8及以上版本)中,只有两个对象有“cascade_iterator”这个属性:sqlalchemy.orm.mapper.Mapper和sqlalchemy.orm.interfaces.MapperProperty。
因为你没有遇到sqlalchemy.orm.exc.UnmappedClassError这个异常(所有的映射器都在正确的位置),我猜测可能是某个内部的SQLAlchemy代码在某个地方得到了None,而它应该得到一个MapperProperty实例。
在导致异常的session.add()调用之前加上类似下面的代码:
from sqlalchemy.orm import class_mapper
from sqlalchemy.orm.interfaces import MapperProperty
props = [p for p in class_mapper(MyObject).iterate_properties]
test = [isinstance(p, MapperProperty) for p in props]
invalid_prop = None
if False in test:
invalid_prop = props[test.index(False)]
然后用你喜欢的方法(比如print、python -m、pdb.set_trace()等)来检查invalid_prop的值。很可能由于某种原因,它不会是None,而这就是问题所在。
如果type(invalid_prop)是sqlalchemy.orm.properties.RelationshipProperty,那么你在映射器配置中引入了一个错误(对于名为invalid_prop.key的关系)。否则,如果没有更多的信息,就很难判断了。
你试过这样做吗:
Column('mtype_id', ForeignKey('mtypes.mtype_id')),
而不是这样:
Column('mtype_id', None, ForeignKey('mtypes.mtype_id')),
另外可以参考: https://docs.sqlalchemy.org/en/13/core/constraints.html