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.

Reply via email to