Design Advice: Multi-Table Inheritance vs. Abstract Base Classes

Hi, all.

I’m currently designing a Django application that will serve as an interface for creating, managing, and practicing different types of flashcards, e.g., front and back, multiple-choice, etc. and am considering how to structure my models. Ideally, each type of flashcard will have its own model, e.g., FrontBackFlashcard, MultipleChoiceFlashcard, etc., and will share several basic attributes.

The resulting application should allow users to practice with sets of flashcards that include multiple flashcard types and the application design should be flexible enough that adding new types in the future does not require significant code changes.

I’m currently leaning toward multi-table inheritance together with the third-party app django-polymorphic because this would make it relatively simple on the backend to interact with all types of flashcards.

However, I am concerned about the performance implications of the “inner joins” that will happen with each of my ORM queries but I lack the experience with relational databases in general to know whether this concern warrants an abstract-base-class approach instead. The latter would presumably require more code relating to my ORM queries and be more complicated to maintain.

Would anyone with more Django and/or relational database experience have advice on how to best approach this?

Thanks in advance!

Welcome!

In general, unless you’re talking about 1,000,000+ cards, performance implications of individual queries should not be a concern regardless of what you design.

Have you designed what the models are for the individual card types? Or at least identified the specific functionality required of them? (I’m not talking about Django / Python code here. I’m referring to a <your native language> document identifying what each card type needs to contain and how they’re going to be used within your system. The more details you are able to define here, the easier the rest of this process will be for you.)

You should first design the cards, then look at the commonalities to see what can be factored out.

Once you’ve designed all your currently-known card types, and have an idea of how they are intended to be “created, managed, and practiced”, then you can design the models to implement them.

One element that is important for you to understand when designing these models are the relationships among them. For example, are there any logical groupings among sets of cards? If so what are they? (e.g., level of difficulty, subcategories of subjects, themantic elements) Are there any sort of sequencing among these groups?

Your models need to be designed to handle this type of “metadata” that may be associated with the cards, and that information might affect your model design as well.

So think about this in the abstract first.

Identify the pages and sequence of events that need to occur. Identify the roles associated with those pages. (For example, are the people who are creating these cards the same people that will be practicing from them?) Identify the data needing to be kept. This goes beyond the cards themselves. Are you looking to track progress? Allow people to select, skip or avoid certain cards, or categories?

Then, once you’ve identified everything that this system will do at some point in time when you’re “done”, trim this down to the absolute minimum functionality that you need to consider this “started”.

Design the models for the “ultimate” solution, but implement only what you need for the first release.

Thank you, Ken! This is a helpful guide and I truly appreciate the thoughtful response.

Multi-Table Inheritance with django-polymorphic:

  • Pros:
    • Simplifies querying across different flashcard types.
    • Makes it easier to add new flashcard types without altering existing schema.
  • Cons:
    • The “inner joins” required can impact performance, especially as the dataset grows.
    • More complex database schema.

Abstract Base Class:

  • Pros:
    • Avoids the need for “inner joins” and can offer better performance.
    • Each model can be optimized independently.
  • Cons:
    • More complex ORM queries.
    • Adding new fields to all flashcard types requires changes to each model.