On Fri, Sep 22, 2017 at 8:18 AM, John Smith <johnsmith31...@gmail.com> wrote:
> I have the following database schema:
>
> Table "Parent":
> 1. id - primary key identifier.
> 2. type - polymorphic_identity.
> 3. name - string data column.
>
> Table "Child"  - inherits Parent:
> 1. id - primary key identifier.
> 2. parent_id - foreignkey to Parent.
> 3. category - string data column.
>
> Summing up I have two tables. Table Child inherits from Parent and also have
> a foreignkey to it.
> I really need both inheritance and foreignkey. This example is only a short
> demo which reproduces the problem.
> My real database has 1000+ tables with complex inheritance.
>
> I used declarative_base to declare the schema:
>
>
>> # -*- coding: utf-8 -*-
>>
>> from sqlalchemy import Column, String, Integer, ForeignKey
>> from sqlalchemy.orm import relationship
>> from sqlalchemy.ext.declarative import declarative_base
>> from sqlalchemy import create_engine
>> from sqlalchemy.orm import sessionmaker
>>
>> Base = declarative_base()
>>
>> class Parent(Base):
>>   __tablename__ = "Parent"
>>   id = Column(Integer, primary_key=True)
>>   type = Column(String(250))
>>
>>   name = Column(String(250))
>>
>>   __mapper_args__ = {
>>     'polymorphic_identity':'Parent',
>>     'polymorphic_on':type
>>   }
>>
>> class Child(Parent):
>>   __tablename__ = 'Child'
>>   id = Column(Integer, ForeignKey('Parent.id'), primary_key=True)
>>
>>   parent_id = Column(ForeignKey("Parent.id"), nullable=True)
>>   category = Column(String(250))
>>
>>   __mapper_args__ = {
>>     'polymorphic_identity':'Child',
>>   }
>>
>> engine = create_engine('postgresql+psycopg2://joe:joe@localhost/alch')
>>
>> session = sessionmaker()
>> session.configure(bind=engine)
>> Base.metadata.create_all(engine)
>
>
> But when I run the code I get the following error:
>
>
>> sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between
>> 'Parent' and 'Child'; tables have more than one foreign key constraint
>> relationship between them. Please specify the 'onclause' of this join
>> explicitly.
>
>
> I have tried to set relationship attribute for Parent or for Child
> separately and for both too. Tried to use primaryjoin and foreign_keys
> parameters of relationship. But the error was the same.
>
> I'm totally confused about this error.
> Please help. Thanks.
>

The docs at http://docs.sqlalchemy.org/en/latest/orm/inheritance.html say:

    It is most common that the foreign key constraint
    is established on the same column or columns
    as the primary key itself, however this is not
    required; a column distinct from the primary key
    may also be made to refer to the parent via foreign
    key. The way that a JOIN is constructed from the
    base table to subclasses is also directly
    customizable, however this is rarely necessary.

The last sentence is the important one. Normally there is only a
single foreign key from the child to the parent table, so SA can
automatically figure out the join condition. In your case, you've got
2 foreign keys, so SA is asking you to be explicit. However, it's the
*inheritance* join that is causing the problem, and the main docs
don't describe how to customize that.

However, if you look at the docs for the underlying mapper() function,
you'll find an "inherit_condition" parameter:

http://docs.sqlalchemy.org/en/latest/orm/mapping_api.html#sqlalchemy.orm.mapper.params.inherit_condition

Unfortunately it doesn't seem to accept strings, so you need to
construct your code such that you have direct access to the classes
themselves.

Here's a working version of your script:

# -*- coding: utf-8 -*-

from sqlalchemy import Column, String, Integer, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class Parent(Base):
  __tablename__ = "Parent"
  id = Column(Integer, primary_key=True)
  type = Column(String(250))

  name = Column(String(250))

  __mapper_args__ = {
    'polymorphic_identity':'Parent',
    'polymorphic_on':type
  }

class Child(Parent):
  __tablename__ = 'Child'
  id = Column(Integer, ForeignKey('Parent.id'), primary_key=True)

  parent_id = Column(ForeignKey("Parent.id"), nullable=True)
  category = Column(String(250))

  parent = relationship(Parent, foreign_keys=[parent_id])

  __mapper_args__ = {
    'polymorphic_identity':'Child',
    'inherit_condition': id == Parent.id,
  }

engine = create_engine('sqlite:///:memory:', echo=True)

Session = sessionmaker()
Session.configure(bind=engine)
Base.metadata.create_all(engine)

session = Session()
parent = Parent(name='Bob')
child = Child(name='Joe', category='cheese')
session.add_all([parent, child])
session.flush()


Hope that helps,

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