在反射之后在SQLAlchemy中添加多对多关系

时间:2017-12-10 11:33:30

标签: python sqlalchemy many-to-many

关注documentation,我已定义并填充了以下表格,但尚未定义任何关系。

class CountryAssociation(Base):
    __tablename__ = 'Country_Region_Mapping'
    country_id = Column(Integer, ForeignKey('countries.uid'), primary_key=True)
    region_id = Column(Integer, ForeignKey('regions.uid'), primary_key=True)
    region = relationship('Region', back_populates='country')
    country = relationship('Countries', back_populates='region')
    extra_data = Column(String(50))

class Countries(Base):
    __tablename__ = 'countries'
    uid = Column(Integer, primary_key=True)
    countryname = Column('English_short_name', 
           String(255), unique=True, nullable=False) 
    region = relationship('CountryAssociation',
            back_populates='country') 

class Region(Base):
    __tablename__ = 'regions'
    uid = Column(Integer, primary_key=True)
    region = Column(String(255), unique=True, nullable=False)
    country = relationship('CountryAssociation', 
        back_populates='region')

我现在想要在表之间创建多对多的关系。 docs

Base = automap_base() #reflecting the orm way
engine = create_engine('sqlite:///mydatabse.db')

Base.prepare(engine, reflect=True)

Session = sessionmaker(bind=engine)
session = Session()

table_countries = Base.classes.countries
table_regions = Base.classes.regions

r = session.query(table_regions).filter(table_regions.region == "Western Europe").first()
c = session.query(table_countries).filter(table_countries.English_short_name == "Germany").first()

c.region.append(r) # this fails with 

AttributeError:'countries'对象没有属性'region'

然而这有效:

c.countryname # Germany

我不知道我在这里做错了什么(初学者)......

1 个答案:

答案 0 :(得分:0)

由于您已将association object patternextra_data一起使用,因此自动relationship detection无法将Country_Region_Mapping识别为secondary table of a many to many

  
      
  1. 如果表包含两个且恰好两个ForeignKeyConstraint个对象,并且此表中的所有列都是这两个ForeignKeyConstraint对象的成员,则该表将被假定为“辅助”表,并且无法直接映射
  2.   

换句话说:并非Country_Region_Mapping中的所有列都是外键约束的成员,因此表不是次要,因此不会创建多对多的关系。

你忽略的另一件事是naming scheme。如果您有一个工作的辅助表,那么创建的关系将是named regions_collection by default(因为复数表名称)。

regionsCountry_Region_Mapping以及countriesCountry_Region_Mapping之间创建的多对一/一对多关系会发生什么:

In [22]: table_countries.country_region_mapping_collection
Out[22]: <sqlalchemy.orm.attributes.InstrumentedAttribute at 0x7f2d600fb258>

In [23]: table_regions.country_region_mapping_collection
Out[23]: <sqlalchemy.orm.attributes.InstrumentedAttribute at 0x7f2d600fbaf0>

In [28]: table_country_region_mapping.countries
Out[28]: <sqlalchemy.orm.attributes.InstrumentedAttribute at 0x7f2d535a2990>

In [29]: table_country_region_mapping.regions
Out[29]: <sqlalchemy.orm.attributes.InstrumentedAttribute at 0x7f2d535a2938>

请注意,由于多个表命名,Country_Region_Mapping上的标量关系属性也有多个命名。

考虑到这些,您需要添加一个新的关联:

In [36]: c.country_region_mapping_collection.append(
    ...:     Base.classes.Country_Region_Mapping(countries=c, regions=r))