On Wed, Nov 15, 2017 at 12:10 AM, Mike Bayer <mike...@zzzcomputing.com> wrote: > On Tue, Nov 14, 2017 at 2:58 PM, Olaf <bastien...@gmail.com> wrote: >> Hello everybody. >> >> Is it possible to have the following relationships between three classes >> (Animal, Car, Description) ? >> >> * An animal has an attribute description >> * A car has an attribute description >> * Each description contains his parent as an attribut. So parent can be a >> car or an animal >> >> Here is my code : >> >> from sqlalchemy import create_engine >> from sqlalchemy.orm import sessionmaker >> from sqlalchemy.ext.declarative import declarative_base >> from sqlalchemy import Column, Integer, String, ForeignKey >> from sqlalchemy.orm import relationship >> >> >> Base = declarative_base() >> >> >> class Description(Base): >> __tablename__ = "descriptions" >> id = Column(Integer, primary_key=True) >> name = Column(String) >> >> >> def __init__(self, name): >> self.name = name >> self.parent = None >> >> >> def __repr__(self): >> return self.name >> >> >> class Animal(Base): >> __tablename__ = "animals" >> id = Column(Integer, primary_key=True) >> name = Column(String) >> id_description = Column(Integer, ForeignKey("descriptions.id"), nullable >> = False) >> description = relationship("Description", backref = "parent") >> >> >> def __init__(self, name): >> self.name = name >> >> >> def __repr__(self): >> return self.name >> >> >> class Car(Base): >> __tablename__ = "cars" >> id = Column(Integer, primary_key=True) >> name = Column(String) >> id_description = Column(Integer, ForeignKey("descriptions.id"), nullable >> = False) >> description = relationship("Description", backref = "parent") >> >> >> def __init__(self, name): >> self.name = name >> >> >> def __repr__(self): >> return self.name >> >> >> >> >> engine = create_engine('YOUR DATABASE', echo = True) >> >> >> Base.metadata.create_all(engine) >> >> Session = sessionmaker(bind=engine) >> session = Session() >> >> rex = Animal("Rex") >> swift = Car("Suzuki Swift") >> >> d1 = Description("Rex is a good dog.") >> d2 = Description("What a beautiful car !") >> >> rex.description = d1 >> d1.parent = rex >> swift.description = d2 >> d2.parent = swift >> >> session.add(rex) >> session.add(swift) >> session.add(d1) >> session.add(d2) >> >> session.commit() >> >> >> >> Error : >> >> Traceback (most recent call last): >> File "C:\Users\user\Desktop\test.py", line 56, in <module> >> rex = Animal("Rex") >> File "<string>", line 2, in __init__ >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\instrumentation.py", >> line 347, in _new_state_if_none >> state = self._state_constructor(instance, self) >> File "C:\Python34\lib\site-packages\sqlalchemy\util\langhelpers.py", line >> 767, in __get__ >> obj.__dict__[self.__name__] = result = self.fget(obj) >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\instrumentation.py", >> line 177, in _state_constructor >> self.dispatch.first_init(self, self.class_) >> File "C:\Python34\lib\site-packages\sqlalchemy\event\attr.py", line 256, >> in __call__ >> fn(*args, **kw) >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\mapper.py", line 3129, >> in _event_on_first_init >> configure_mappers() >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\mapper.py", line 3019, >> in configure_mappers >> mapper._post_configure_properties() >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\mapper.py", line 1810, >> in _post_configure_properties >> prop.init() >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\interfaces.py", line >> 184, in init >> self.do_init() >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\relationships.py", line >> 1661, in do_init >> self._generate_backref() >> File "C:\Python34\lib\site-packages\sqlalchemy\orm\relationships.py", line >> 1851, in _generate_backref >> (backref_key, self, m)) >> sqlalchemy.exc.ArgumentError: Error creating backref 'parent' on >> relationship 'Animal.description': property of that name exists on mapper >> 'Mapper|Description|descriptions' >> >> >> It seems impossible to link the classes to the same attribute "parent" in >> the class "Description". Is there a solution ? > > > you're attempting a pattern we call "generic association" (I've also > called it "polymorphic association") - a single destination item that > can be referred to by many types of objects. I've documented three > ways of doing these, noting that one of them is a common pattern from > the Django / Rails world, though I don't recommend that one. Unless > you need to query for descriptions across Dogs/Cars at the same time, > I'd go with table_per_related. The mental exercise here is being OK > with the fact that there are more tables than you thought there would > be. It "feels" wrong to have multiple tables with the same columns > but there's actually nothing wrong with it at all. Your source code > need not have any repetition in it. >
Here's the link to the docs: http://docs.sqlalchemy.org/en/latest/orm/examples.html#module-examples.generic_associations Simon -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.