On Jun 28, 2012, at 6:38 AM, tonthon wrote:

> Hi,
> 
> I've got a problem understanding how to handle relationships with
> polymorphism
> Sorry for the db design (I took it overs as it is ).
> 
> I've got a parent class Task
> 
> class Task(DBBASE):
>    __tablename__ = 'task'
>    id = Column(Integer, primary_key=True)
>    amount = Column(Integer)
> 
> and two child classes
> 
> class Invoice(DBBASE):
>    __tablename__ = 'invoice'
>    id = Column(Integer, ForeignKey('task.id'), primary_key=True)
>    date = Column(Date)
>    project_id = Column(Integer, ForeignKey('project.id'))
>    project = relationship("Project", backref=backref('invoices',
> order_by='Invoice.date'))
>    specific_attr1 = Column(Integer)
> 
> class Esimation(DBBASE):
>    __tablename__ = 'estimation'
>    id = Column(Integer, ForeignKey('task.id'), primary_key=True)
>    date = Column(Date)
>    project_id = Column(Integer, ForeignKey('project.id'))
>    project = relationship("Project", backref=backref('estimations',
> order_by='Invoice.date'))
>    specific_attr2 = Column(Integer)
>    specific_attr3 = Column(Integer)
> 
> I'd like to query something like:
> 
> dbession.query(Task).with_polymorphic([Invoice,
> Estimation]).join(Invoice.project).join(Estimation.project).join(Project.client)
> 
> I actually get an error :
> (1066, "Not unique table/alias: 'project' ")

OK you need here to think about SQL.   Task, Invoice, Estimation are all 
different tables.    A particular row in Task will either have an Invoice, or 
Estimation row - but never both.  So with_polymorphic() implies an outer join 
from Task to both of these tables.

Once you're outer joining, anything that you join to from those joins, also 
needs to be an outer join else you'll get no rows back when the parent is NULL 
- so we are talking about Invoice.project as well as Estimation.project, and 
also each of those to Project.client - unfortunately you'll have to also join 
to client twice if you really need all of these columns present.    The "not 
unique" error refers to the fact that a particular name can only be mentioned 
as a FROM target once in SQL.

So you'll need to alias out those targets, like this:

p1 = aliased(Project)
p2 = aliased(Project)

then use outerjoins and distinct joins to client:

query(Task).with_polymorphic([Invoice, Estimation]).outerjoin(p1, 
Invoice.project).outerjoin(p2, 
Estimation.Project).outerjoin(p1.client).outerjoin(p2.client)

the above query has a lot of outer joins and is generally not going to perform 
very well.  Depending on what you're ultimately trying to do, you may want to 
join to a union of the estimation/invoice->project->client target, if you're 
looking to have a simple path from Task to Client  (that is, 
query(Task).join(my_union, Task.id=my_union.c.id), and I'd create my_union 
using Table/select() objects directly for "select client.* from 
invoice_table->project->client UNION select client.* from 
estimation_table->project_client".    I'd experiment with SQL directly to see 
what works best.

(also this is joined inheritance, not concrete, since Invoice/Estimation join 
to Task with the "task.id" FK).


-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.

Reply via email to