How to store different payment types using multi-table inheritance in single Order model?

I am currently considering how to best model purchase order-related data for a project that I would like to build and would appreciate any design advice for the following data modeling challenge:

  • Challenge: I would like to unify all purchase order-related data in a single model, e.g., Order. However, orders can be paid for with several payment methods and each method requires storing data that is unique to that method, e.g., credit card, cash, cryptocurrency, etc. In some cases, orders may also be paid for with more than one payment method and in multiple transactions.

  • Partial Solution: I will use multi-table inheritance to create a base payment method model, e.g., Payment, with the universally shared fields and then create more specific method models that inherit from it, e.g., CreditCardPayment, CashPayment, CryptocurrencyPayment, etc.

  • Problem: I am stuck at how best to link the different payment method models back to the Order model. Ideally, I would like to be able to access all Payment child model objects from a single field. Would this be accomplishable with a ForeignKey field to the Payment model or does this case require the use of a GenericForeignKey via the contenttypes framework?

First, no. This does not require using a GFK, and I would recommend against it.

Your basic idea is good. (A parent Payment model with CreditCard, Cash, etc as models inheriting from it.)

It’s the Payment model that will have the FK to Order. Then, from an instance of Order, you can access all the individual Payment.

The only question at that point is identifying which of the payment types exist. Since each of the payment type models have a OneToOne field back to Payment, you would need to check for the existance of the related models from an instance of Payment.

Note: This structure also allows multiple payment types for an individual Payment, but only one of each. If you need to provide for multiple instances of an individual payment type for a single payment, then you would not use multi-table inheritance - you would have a ForeignKey in the payment type referencing Payment. (This is a “business requirements” architectural decision and not a technical issue.)

If this is a case where there can only be one payment type for a payment, and that this will never change once it has been created, and the number of payment types is variable based on different installations of this software, and the number of possible payment types gets sufficiently large, then I might think about a denormalized structure where the Payment model has a payment_type field identifying the class of the payment type to which it is related to mitigate some of the complexity that may evolve from this.

Hi, Ken. Thank you for the thorough reply! This now makes much more sense.