Thanks for the response! The solution looks too hairy for my tastes, and
I can manage with what I currently have. Good to know it's possible though!
10.07.2015, 02:25, Mike Bayer kirjoitti:
On 7/9/15 12:17 PM, Alex Grönholm wrote:
Thanks. What about my other question? Is it possible to have two
layers of classes (Document and ContactDocument) mapped to
polymorphic unions?
OK. So, AbstractConcreteBase struggles hard against Declarative
wanting to map things. So as far as how to get it to take effect
multiple times in a hierarchy, with ABC itself it would require more
weird class tricks, of the kind where we always have to see, "does
class A declare "_x" or is it inheriting it?" which is why declarative
has gotten so crazy compared to its innocent beginnings. This
might be something that can be added but I'd have to think about it,
ABC is still pretty brittle overall.
I can have you just use the API that ABC uses internally. Concrete
mappings in classical SQLA were really easy, because we had those
Table objects up front before we did anything with the classes. With
declarative we don't have that because it makes the table/mapper at
the same time. This architecture has opened up a lot in 1.0 but
still doesn't make this kind of thing that simple. But the main thing
that was added probably in 0.8 or 0.9 to make this possible was a way
to attach the "base" underneath a concrete mapper after the subclass
is set up. Instead of ABC doing that for us, we can do it the "old"
way manually, using polymophic_union() in the old way and calling
mapper(), just using one newish API function so that we can still use
declarative for the subclasses. It's one private API function at the
moment. It maps and creates the queries, so that should be pretty much
it - we can try to make these API patterns more accessible. Let me
know if this works more fully.
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.declarative.api import declared_attr
from sqlalchemy.orm import configure_mappers, mapper, Session
from sqlalchemy.sql.schema import Column, ForeignKey
from sqlalchemy.sql.sqltypes import Date, String, Integer
Base = declarative_base()
class Company(Base):
__tablename__ = 'companies'
id = Column(Integer, primary_key=True)
class Document(Base):
date = Column(Date)
documentType = Column(String)
__abstract__ = True
__mapper_args__ = {"concrete": True}
class SomeDocument(Document):
"""extends Document but not ContactDocument """
__tablename__ = 'some_document'
id = Column(Integer, primary_key=True)
class ContactDocument(Document):
contactPersonName = Column(String)
salesPersonName = Column(String)
sendMethod = Column(String)
@declared_attr
def company_id(self):
return Column(ForeignKey('companies.id'))
__abstract__ = True
class Offer(ContactDocument):
__tablename__ = 'offers'
id = Column(Integer, primary_key=True)
class SalesOrder(ContactDocument):
__tablename__ = 'orders'
id = Column(Integer, primary_key=True)
from sqlalchemy.orm.util import polymorphic_union
document_pjoin = polymorphic_union({
'offer': Offer.__table__,
'orders': SalesOrder.__table__,
'somedocument': SomeDocument.__table__
}, 'type', 'd_pjoin'
)
contact_document_pjoin = polymorphic_union({
'offer': Offer.__table__,
'orders': SalesOrder.__table__,
}, 'type', 'cd_pjoin'
)
md = mapper(
Document,
document_pjoin,
polymorphic_on=document_pjoin.c.type,
concrete=True)
mcd = mapper(
ContactDocument,
contact_document_pjoin,
inherits=md,
polymorphic_on=contact_document_pjoin.c.type,
concrete=True)
# AbstractConcreteBase does this part by looking at cls.__subclasses__()
Offer.__mapper__._set_concrete_base(mcd)
SalesOrder.__mapper__._set_concrete_base(mcd)
SomeDocument.__mapper__._set_concrete_base(md)
configure_mappers()
session = Session()
print "-----------"
print session.query(Document)
print "-----------"
print session.query(ContactDocument)
torstai 9. heinäkuuta 2015 18.31.36 UTC+3 Michael Bayer kirjoitti:
Thanks for reporting. Issue
https://bitbucket.org/zzzeek/sqlalchemy/issues/3480/abstractconcretebase-regression-with
is created, create the Column objects with an explicit key for now:
class Document(object):
date = Column(Date)
documentType = Column('documenttype', String, key="documentType")
class ContactDocument(AbstractConcreteBase, Base, Document):
contactPersonName = Column('contactpersonname', String,
key="contactPersonName")
salesPersonName = Column(String)
sendMethod = Column('sendmethod', String, key="sendMethod")
@declared_attr
def company_id(self):
return Column(ForeignKey('companies.id
<http://companies.id>'))
On 7/9/15 11:18 AM, Alex Grönholm wrote:
The following script no longer works in 1.0.6, but does in 0.9.9:
fromsqlalchemy.ext.declarativeimportdeclarative_base, AbstractConcreteBase
fromsqlalchemy.ext.declarative.apiimportdeclared_attr
fromsqlalchemy.orm.mapperimportconfigure_mappers
fromsqlalchemy.orm.sessionimportSession
fromsqlalchemy.sql.schemaimportColumn, ForeignKey
fromsqlalchemy.sql.sqltypesimportDate, String, Integer
Base = declarative_base()
classCompany(Base):
__tablename__ ='companies'
id = Column(Integer,primary_key=True)
classDocument(object):
date = Column(Date)
documentType = Column('documenttype', String)
classContactDocument(AbstractConcreteBase, Base, Document):
contactPersonName = Column('contactpersonname', String)
salesPersonName = Column(String)
sendMethod = Column('sendmethod', String)
@declared_attr
defcompany_id(self):
returnColumn(ForeignKey('companies.id <http://companies.id>'))
classOffer(ContactDocument):
__tablename__ ='offers'
id = Column(Integer,primary_key=True)
classSalesOrder(ContactDocument):
__tablename__ ='orders'
id = Column(Integer,primary_key=True)
configure_mappers()
session = Session()
query = session.query(ContactDocument)
print(query)
On 1.0.6, I get an error: sqlalchemy.exc.ArgumentError: When
configuring property 'documentType' on
Mapper|ContactDocument|pjoin, column 'documenttype' is not
represented in the mapper's table. Use the `column_property()`
function to force this column to be mapped as a read-only attribute.
Why am I getting this? Is this a bug or am I not understanding
something?
Also, is it possible to have both Document and ContactDocument
as abstract concrete base classes (ie. I want the union from
Document to include both the direct concrete subclasses of
Document and all concrete subclasses of ContactDocument as well)?
--
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 [email protected] <javascript:>.
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
--
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 [email protected]
<mailto:[email protected]>.
To post to this group, send email to [email protected]
<mailto:[email protected]>.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to a topic in the
Google Groups "sqlalchemy" group.
To unsubscribe from this topic, visit
https://groups.google.com/d/topic/sqlalchemy/U8mpVm8udi8/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
[email protected]
<mailto:[email protected]>.
To post to this group, send email to [email protected]
<mailto:[email protected]>.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
--
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.