Suppose you have to model several classes that should have composite properties like dimensions (width and height) or phone number (prefix, number and extension).
In Java (using JPA 2) I’d create a Dimensions class and annotate it with @Embeddable. This causes Dimension’s fields (e.g. width and height) to be embedded into every class that declares a property of type Dimensions.
How do you model these with Django while avoiding code duplication? It doesn’t make sense to create a separate Dimensions model and reference it with a ForeignKey field. And the classes do not have enough in common to justify model inheritance.
I think you might be over-thinking inheritance. Inheritance is and is actually the recommended method to composite models. The following is an example of how properly use model inheritance in Django:
So what this does is it creates a model
PhoneModelBase, however the key here is that it usesclass Metawithabstract=True.Here is more of behind the scenes of what is going on and some explanation of some of the Python concepts. I assume that you are not aware of them since you mentioned Java in the question. These Python concepts are actually rather confusing concepts so my explanation is probably not full, or even confusing, so if you will not follow, don’t mind. All you have to know is to use
abstact = True. Here is the official doc: https://docs.djangoproject.com/en/dev/topics/db/models/#abstract-base-classes.Metaattribute withinPhoneModelBaseis just that, an attribute. It is the same as any other attribute within the class, except its a class instance (remember that in Python classes and functions are first order members). In addition, Python has this thing called__metaclass__which you can add to you classes.__metaclass__defines a way of how an instance of a class is build. More about that here. Django uses these in how it creates model class instances.So to create the
PhoneModelBaseclass, the following is a rough outline:PhoneModelBaseclass (the class itself, not instance of class –PhoneModelBase()) is being created, the__metaclass__which comes frommodel.Modeldue to inheritance takes over the creation process__metaclass__, Python calls the function which creates the actual class instance and passes to it all of the fields from the class you are trying to create – PhoneModelBase. That will includephone,Metaand any other fields you defineMetaattribute and then it starts analyzing its attributes. According to the values of these attributes, Django will change the behavior of the modelabstractattribute and then changes the logic of the class its trying to create –PhoneModelBaseby not storing it in dbSo then the
PhoneModelBase, even though its definition looks very similar to a regular model, its not a regular model. It is just an abstract class which is meant to be used as composite in other models.When other models inherit from
PhoneModelBase, their__metaclass__will copy the attributes from the base model as if you manually typed those attributes. It will not be a foreign key on anything like that. All of the inherited attributes are going to be a part of the model and will be in the same table.Hopefully all of this makes some sense. If not, all you have to remember is just to use
Metaclass withabstract = True.EDIT
As suggested in the comment, you can also inherit from multiple base classes. So you can have
PhoneModelBase,DimensionsModelBase, and then you can inherit from both of these (or more), and all of the attributes from all base classes will be present in your model.