Ok I've got it - Is this the best way to do it? - I created a generic id field table as such:
class PaymentDetails(Base):
__tablename__ = 'payment_details'
id = Column(Integer, primary_key=True)
type = Column(PaymentType.db_type(), nullable=False)
where PaymentType
uses the declarative enum recipe and and then subclassed this for the various payment methods:
@concrete
@do_unique_index('paypal_unique_details', 'env', 'main_email', 'sub_email')
class Paypal(Base):
__tablename__ = 'paypal_details'
id = Column(ForeignKey('payment_details.id'), primary_key=True)
# The rest of the implementation
#
@concrete
@do_unique_index('credit_card_unique_details', 'env', 'card_number')
class CreditCard(Base):
__tablename__ = 'card_details'
id = Column(ForeignKey('payment_details.id'), primary_key=True)
# The rest of the implementation
#
@concrete
@do_unique_index('time_code_unique_details', 'env', 'code')
class TimeCodes(Base):
__tablename__ = 'code_details'
id = Column(ForeignKey('payment_details.id'), primary_key=True)
# The rest of the implementation
#
(Where concrete
and do_unique_index
set the relevant __mapper_args__
and __table_args__
). I then set the description field of the PaymentType
enum values to be each of these classes, so that to look up a payment I can query for a PaymentDetails
object, then get an id and a type from that, say id
and Paypal
, to perform a second query for the Paypal
with that id.
My code for adding sets of details is fairly simple in that in a single transaction, it adds the next logical id to the PaymentDetails
table with the type of the payment details we are trying to create, and then adds an entry to that table with the details I want to enter. I can then add methods to these ORM classes to handle the different ways that we would handle buying, selling, and refunding for each method, such that they can be treated as identical.
You then need to switch on FK constraints as van mentioned - I did so by adding the FK listener to the helper class I use for DB access.