`sqlalchemy.exc.InvalidRequestError:使用SQLAlchemy-Continuum扩展

时间:2015-09-07 12:37:27

标签: python sqlalchemy sqlalchemy-continuum

当我尝试使用SQLAlchemy-Continuum扩展到SQLAlchemy从Kotti项目中对表进行版本化时遇到sqlalchemy.exc.InvalidRequestError: Implicitly combining column(...)错误。这些表使用连接表继承方法模拟继承。基于Kotti的原始代码,我创建了最小的测试用例来显示问题(下面是test.py)。在文件内容之后的追溯中可以看到错误,如下所示:

  

sqlalchemy.exc.InvalidRequestError:在属性' transaction_id'下隐式地将列contents_version.transaction_id与列nodes_version.transaction_id组合在一起。请明确为这些同名列配置一个或多个属性。

正如最后一个调试行所说

  

INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion | documents_version)_configure_property(transaction_id,Column)

很明显,在配置transaction_id模型的DocumentVersion属性期间发生了错误。此模型由SQLAlchemy-Continuum扩展自动创建,以跟踪原始Document模型中的更改。我想SQLAlchemy-Continuum扩展没有正确处理这种情况(连接表继承),但我不知道如何解决这个问题。我已经阅读了SQLAlchemy的FAQ标题为I’m getting a warning or error about “Implicitly combining column X under attribute Y”的条目,但鉴于错误来自扩展程序,我仍然不知道在哪里修复此问题。

我在SQLAlchemy-Continuum的跟踪器here和SQLAlchemy here的邮件列表上提出了这个问题但尚未回复。

SQLAlchemy-Continuum 1.2.0,SQLAlchemy 1.0.8

test.py

import logging
from sqlalchemy import (Column, ForeignKey, Integer, String)
from sqlalchemy.ext.declarative import (declarative_base, declared_attr)
from sqlalchemy.orm import configure_mappers
from sqlalchemy.util import classproperty
from sqlalchemy_continuum import make_versioned

logging.basicConfig()
logging.getLogger('sqlalchemy.orm').setLevel(logging.INFO)
make_versioned(user_cls=None)

class Node(declarative_base()):
    __versioned__ = {}
    __mapper_args__ = dict(polymorphic_on='type',
        polymorphic_identity='node',
        with_polymorphic='*')

    @declared_attr
    def __tablename__(cls):
        return '{0}s'.format(cls.__name__.lower())

    id = Column(Integer(), primary_key=True)
    type = Column(String(30), nullable=False)

class Content(Node):
    __versioned__ = {}

    @classproperty
    def __mapper_args__(cls):
        return dict(polymorphic_identity=cls.__name__.lower())

    id = Column(Integer, ForeignKey('nodes.id'), primary_key=True)

class Document(Content):
    __versioned__ = {}
    id = Column(Integer(), ForeignKey('contents.id'), primary_key=True)

configure_mappers()

输出和追溯:

INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) _configure_property(id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) _configure_property(type, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) Identified primary key columns: ColumnSet([Column('id', Integer(), table=<nodes>, primary_key=True, nullable=False)])
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) constructed
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) _configure_property(id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) _configure_property(type, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) _configure_property(id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) inserting column to existing list in properties.ColumnProperty id
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) constructed
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) _configure_property(id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) _configure_property(type, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) _configure_property(id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) inserting column to existing list in properties.ColumnProperty id
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) constructed
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) _post_configure_properties() started
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) initialize prop id
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) initialize prop type
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) _post_configure_properties() complete
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) _post_configure_properties() started
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) initialize prop id
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) initialize prop type
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) _post_configure_properties() complete
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) _post_configure_properties() started
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) initialize prop id
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) initialize prop type
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) _post_configure_properties() complete
INFO:sqlalchemy.orm.mapper.Mapper:(Transaction|transaction) _configure_property(issued_at, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(Transaction|transaction) _configure_property(id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(Transaction|transaction) _configure_property(remote_addr, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(Transaction|transaction) Identified primary key columns: ColumnSet([Column('id', BigInteger(), table=<transaction>, primary_key=True, nullable=False)])
INFO:sqlalchemy.orm.mapper.Mapper:(Transaction|transaction) constructed
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) _configure_property(id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) _configure_property(type, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) _configure_property(transaction_id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) _configure_property(end_transaction_id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) _configure_property(operation_type, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) Identified primary key columns: ColumnSet([Column('id', Integer(), table=<nodes_version>, primary_key=True, nullable=False), Column('transaction_id', BigInteger(), table=<nodes_version>, primary_key=True, nullable=False)])
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) constructed
INFO:sqlalchemy.orm.mapper.Mapper:(Node|nodes) _configure_property(versions, RelationshipProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(Content|contents) _configure_property(versions, RelationshipProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(Document|documents) _configure_property(versions, RelationshipProperty)
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions setup primary join nodes.id = nodes_version.id
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions setup secondary join None
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions synchronize pairs [(nodes.id => nodes_version.id)]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions secondary synchronize pairs []
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions local/remote pairs [(nodes.id / nodes_version.id)]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions remote columns [nodes_version.id]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions local columns [nodes.id]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:Node.versions relationship direction symbol('ONETOMANY')
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) _configure_property(version_parent, RelationshipProperty)
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent setup primary join nodes.id = nodes_version.id
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent setup secondary join None
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent synchronize pairs [(nodes.id => nodes_version.id)]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent secondary synchronize pairs []
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent local/remote pairs [(nodes_version.id / nodes.id)]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent remote columns [nodes.id]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent local columns [nodes_version.id]
INFO:sqlalchemy.orm.relationships.RelationshipProperty:NodeVersion.version_parent relationship direction symbol('MANYTOONE')
INFO:sqlalchemy.orm.strategies.LazyLoader:NodeVersion.version_parent lazy loading clause nodes.id = :param_1
INFO:sqlalchemy.orm.strategies.LazyLoader:NodeVersion.version_parent will use query.get() to optimize instance loads
INFO:sqlalchemy.orm.strategies.LazyLoader:Node.versions lazy loading clause :param_1 = nodes_version.id
INFO:sqlalchemy.orm.mapper.Mapper:(NodeVersion|nodes_version) _configure_property(transaction, RelationshipProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(operation_type, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(transaction_id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(end_transaction_id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(type, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(version_parent, RelationshipProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(transaction, RelationshipProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) _configure_property(id, Column)
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) inserting column to existing list in properties.ColumnProperty id
INFO:sqlalchemy.orm.mapper.Mapper:(ContentVersion|contents_version) constructed
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(operation_type, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(transaction_id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(end_transaction_id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(id, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(type, ColumnProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(version_parent, RelationshipProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(transaction, RelationshipProperty)
INFO:sqlalchemy.orm.mapper.Mapper:(DocumentVersion|documents_version) _configure_property(transaction_id, Column)
Traceback (most recent call last):
  File "/home/piotr/projects/sqlalchemy-continuum/test.py", line 38, in <module>
    configure_mappers()
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2736, in configure_mappers
    Mapper.dispatch._for_class(Mapper).after_configured()
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/event/attr.py", line 218, in __call__
    fn(*args, **kw)
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/orm/events.py", line 550, in wrap
    fn(*arg, **kw)
  File "/home/piotr/projects/sqlalchemy-continuum/sqlalchemy_continuum/builder.py", line 165, in configure_versioned_classes
    self.build_models()
  File "/home/piotr/projects/sqlalchemy-continuum/sqlalchemy_continuum/builder.py", line 87, in build_models
    self.manager.transaction_cls
  File "/home/piotr/projects/sqlalchemy-continuum/sqlalchemy_continuum/model_builder.py", line 263, in __call__
    self.version_class = self.build_model(table)
  File "/home/piotr/projects/sqlalchemy-continuum/sqlalchemy_continuum/model_builder.py", line 250, in build_model
    args
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/api.py", line 55, in __init__
    _as_declarative(cls, classname, cls.__dict__)
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 88, in _as_declarative
    _MapperConfig.setup_mapping(cls, classname, dict_)
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 103, in setup_mapping
    cfg_cls(cls_, classname, dict_)
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 135, in __init__
    self._early_mapping()
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 138, in _early_mapping
    self.map()
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/ext/declarative/base.py", line 529, in map
    **self.mapper_args
  File "<string>", line 2, in mapper
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 627, in __init__
    self._configure_properties()
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1318, in _configure_properties
    setparent=True)
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1525, in _configure_property
    prop = self._property_from_column(key, prop)
  File "/home/piotr/projects/sqlalchemy-continuum/env/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1650, in _property_from_column
    raise sa_exc.InvalidRequestError(msg)
sqlalchemy.exc.InvalidRequestError: Implicitly combining column contents_version.transaction_id with column nodes_version.transaction_id under attribute 'transaction_id'.  Please configure one or more attributes for these same-named columns explicitly.

Process finished with exit code 1

0 个答案:

没有答案