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:
from sqlalchemy.ext.declarativeimport declarative_base, AbstractConcreteBase
from sqlalchemy.ext.declarative.apiimport declared_attr
from sqlalchemy.orm.mapperimport configure_mappers
from sqlalchemy.orm.sessionimport Session
from sqlalchemy.sql.schemaimport Column, ForeignKey
from sqlalchemy.sql.sqltypesimport Date, String, Integer
Base = declarative_base()
class Company(Base):
__tablename__ ='companies' id = Column(Integer,primary_key=True)
class Document(object):
date = Column(Date)
documentType = Column('documenttype', String)
class ContactDocument(AbstractConcreteBase, Base, Document):
contactPersonName = Column('contactpersonname', String)
salesPersonName = Column(String)
sendMethod = Column('sendmethod', String)
@declared_attr def company_id(self):
return Column(ForeignKey('companies.id <http://companies.id>'))
class Offer(ContactDocument):
__tablename__ ='offers' id = Column(Integer,primary_key=True)
class SalesOrder(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]
<javascript:>.
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 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.