Defining models with specializations

Overview

This document describes the customizations you will need to make to your Django models to make the specialization code work. There’s not too much to bear in mind, so the switch should be easy!

Example models

Let us consider the models we defined in Introduction:

from django.db import models

from djeneralize.models import BaseGeneralizationModel
from djeneralize.fields import SpecializedForeignKey


#{ General model


class WritingImplement(BaseGeneralizationModel):

    name = models.CharField(max_length=30)
    length = models.IntegerField()
    holder = SpecializedForeignKey(
        'WritingImplementHolder', null=True, blank=True)

    def __unicode__(self):
        return self.name


#{ Direct children of WritingImplement, i.e. first specialization


class Pencil(WritingImplement):

    lead = models.CharField(max_length=2) # i.e. HB, B2, H5

    class Meta:
        specialization = 'pencil'


class Pen(WritingImplement):

    ink_colour = models.CharField(max_length=30)

    class Meta:
        specialization = 'pen'


#{ Grand-children of WritingImplement, i.e. second degree of specialization


class FountainPen(Pen):

    nib_width = models.DecimalField(max_digits=3, decimal_places=2)

    class Meta:
        specialization = 'fountain_pen'


class BallPointPen(Pen):

    replaceable_insert = models.BooleanField(default=False)

    class Meta:
        specialization = 'ballpoint_pen'


#{ Writing implement holders general model


class WritingImplementHolder(BaseGeneralizationModel):

    name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.name


#{ Writing implement holders specializations


class StationaryCupboard(WritingImplementHolder):

    volume = models.FloatField()

    class Meta:
        specialization = 'stationary_cupboard'


class PencilCase(WritingImplementHolder):

    colour = models.CharField(max_length=30)

    class Meta:
        specialization = 'pencil_case'


#}

Derive your model from BaseGeneralizationModel

The top-level model is derived from djeneralize.models.BaseGeneralizationModel and not django.db.models.Model. Just make sure this class is imported at the top of the module and that’s the inheritance done!

Set up the specialization for your models

You must explicitly declare the specialization that your model exhibits. In most cases the naming can be similar to the class name, but only alphanumeric characters are accepted here.

This declaration should always be done in the inner class Meta declaration.

Note

The top-most sub-class of BaseGeneralizedModel does not require and, in fact, forbids the declaration of a specialization.

These specializations are used by djeneralize to keep track of the relationships between the general case and the specializations. The model calculates a “path” for each specialization with the most general case being assigned the / path. This value is stored on the specialization_type field, so be careful when altering this field.

Warning

If the inheritance scheme changes for your models you will need to create a database migration to ensure that the specialization_type field is correctly mapped to the new structure of your inheritance.