Polymorphic Model Relations

Django Model Relations — 4

Emre Cevik
Python | Django & Rest

--

Before learning about this, you may want to take a look at one-to-one, one -to-many and many-to-many relationships.

POLYMORPHIC ONE-TO-MANY RELATIONSHIP

- Sony can be sound system of many car models
- Pioneer can be sound system of many car models
- Car model can have only one sound system (Sony or Pioneer)

|-------------|---------------|
| Car Model | Sound System |
|-------------|---------------|
| C180 | S1 (SONY) |
| C200 | S1 (SONY) |
| X1 | S2 (SONY) |
| A3 | P1 (PIONEER) |
|-------------|---------------|

Add Sony:

$ from modelrelations.models import CarModel, Sony, Pioneer

$ sony1 = Sony.objects.create(name=”Sony Audio System”)
$ sony2 = Sony.objects.create(name=”Sony High Defination Audio System”)
$ Sony.objects.all()<QuerySet [
<Sony: Sony Audio System>,
<Sony: Sony High Defination Audio System>
]>

Add Pioneer:

$ pioneer1 = Pioneer.objects.create(name=”Pioneer v1 Audio System”)
$ pioneer2 = Pioneer.objects.create(name=”Pioneer v2 Audio System”)
$ Pioneer.objects.all()<QuerySet [
<Pioneer: Pioneer v1 Audio System>,
<Pioneer: Pioneer v2 Audio System>
]>

Associate the CarModel with an Audio System

$ c180 = CarModel.objects.create(name="C180", content_object=sony1)
$ c200 = CarModel.objects.create(name="C200", content_object=sony2)
$ s200 = CarModel.objects.create(name="S200", content_object=sony2)
$ s500 = CarModel.objects.create(name="S500", content_object=pioneer1)
$ CarModel.objects.all()<QuerySet [
<CarModel: C180>,
<CarModel: C200>,
<CarModel: S200>,
<CarModel: S500>
]>
$ c180.content_object<Sony: Sony Audio System>$ c180.content_object.name'Sony Audio System'

Associate the Audio System with a CarModel

$ sony1.carmodels.all()<QuerySet [    
<CarModel: C180>,
]>
$ sony2.carmodels.all()<QuerySet [
<CarModel: C200>,
<CarModel: S200>
]>
$ pioneer1.carmodels.all()<QuerySet [
<CarModel: S500>
]>
$ pioneer2.carmodels.add(c180, s500)
$ pioneer2.carmodels.all()
<QuerySet [
<CarModel: C180>,
<CarModel: S500>
]>
$ sony1.carmodels.all()<QuerySet []>$ pioneer1.carmodels.all()<QuerySet []>

Clear relations

$ sony2.carmodels.clear()
$ sony2.carmodels.all()
<QuerySet []>$ pioneer2.carmodels.clear()
$ pioneer2.carmodels.all()
<QuerySet []>

POLYMORPHIC ONE-TO-MANY RELATIONSHIP WITH DJANGO-POLYMORPHIC PACKAGE

Django-polymorphic builds on top of the standard Django model inheritance. It makes using inherited models easier. When a query is made at the base model, the inherited model classes are returned.

First we need to install django-polymorphic package

pip install django-polymorphic

After installation completes, add polymorphic to INSTALLED_APPS:

# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'polymorphic',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'modelrelations'
]

Making Your Models Polymorphic

Add Sony

$ from modelrelations.models import CarModel, Sony, Pioneer, Audio
$ sony1 = Sony.objects.create(name=”Sony Audio System”)
$ sony2 = Sony.objects.create(name=”Sony High Defination Audio System”)

Add Pioneer

$ pioneer1 = Pioneer.objects.create(name=”Pioneer v1 Audio System”)
$ pioneer2 = Pioneer.objects.create(name=”Pioneer v2 Audio System”)

List Audio Systems

$ Audio.objects.all()<PolymorphicQuerySet [
<Sony: Sony Audio System>,
<Sony: Sony High Defination Audio System>,
<Pioneer: Pioneer v1 Audio System>,
<Pioneer: Pioneer v2 Audio System>
]>

List Only Sony Audio Systems

$ Audio.objects.instance_of(Sony)<PolymorphicQuerySet [
<Sony: Sony Audio System>,
<Sony: Sony High Defination Audio System>
]>

Select CarModels

$ CarModel.objects.all()<QuerySet [
<CarModel: C180>,
<CarModel: C200>,
<CarModel: S200>,
<CarModel: S500>
]>
$ c180 = CarModel.objects.get(id=1)
$ c200 = CarModel.objects.get(id=2)
$ s200 = CarModel.objects.get(id=3)
$ s500 = CarModel.objects.get(id=4)

Associate the Sound System with a CarModel

$ sony1.carmodels.add(c180, c200)
$ pioner1.carmodels.add(s200)
$ sony1.carmodel.all()<QuerySet [
<CarModel: C180>,
<CarModel: C200>
]>
$ pioneer1.carmodels.all()<QuerySet [
<CarModel: S200>
]>

Associate the CarModel with a Sound System

$ s500.audio = pioneer2
$ s500.save()
$ pioneer2.carmodels.all()<QuerySet [
<CarModel: S500>
]>

Clear relations

$ sony2.carmodels.add(c180, c200, s200, s500)
$ sony2.carmodels.all()
<QuerySet [
<CarModel: C180>,
<CarModel: C200>,
<CarModel: S200>,
<CarModel: S500>
]>
$ sony1.carmodels.all()<QuerySet []>$ pioneer1.carmodels.all()<QuerySet []>$ pioneer2.carmodels.all()<QuerySet []>$ sony2.carmodels.clear()
$ sony2.carmodels.all()
<QuerySet []>

POLYMORPHIC MANY-TO-MANY RELATIONSHIP WITH DJANGO-POLYMORPHIC PACKAGE

- 2WD can be drive wheel system of many car models
- 4WD can be drive wheel system of many car models
- Car model can have many drive wheel system (2WD or/and 4WD)

|-------------|---------------|
| Car Model | Drive Wheels |
|-------------|---------------|
| C180 | RWD (2WD) |
| C180 | AWD (4WD) |
| C200 | FWD (2WD) |
| s200 | FWD (2WD) |
| s500 | AWD (4WD) |
|-------------|---------------|

Add Drive System

$ from modelrelations.models import CarModel, Drive, FourWheelDrive, TwoWheelDrive$ rwd = TwoWheelDrive.objects.create(name=”RWD”)
$ fwd = TwoWheelDrive.objects.create(name=”FWD”)
$ awd = FourWheelDrive.objects.create(name=”AWD”)$ Drive.objects.all()<PolymorphicQuerySet [
<TwoWheelDrive: RWD>,
<TwoWheelDrive: FWD>,
<FourWheelDrive: AWD>
]>

Select CarModels

$ CarModel.objects.all()<QuerySet [
<CarModel: C180>,
<CarModel: C200>,
<CarModel: S200>,
<CarModel: S500>]>
$ c180 = CarModel.objects.get(id=1)
$ c200 = CarModel.objects.get(id=2)
$ s200 = CarModel.objects.get(id=3)
$ s500 = CarModel.objects.get(id=4)

Associate the CarModel with a Drive

$ c180.drive.add(rwd, awd)
$ c180.drive.all()
<PolymorphicQuerySet [
<TwoWheelDrive: RWD>,
<FourWheelDrive: AWD>
]>
$ s500.drive.add(awd, fwd, rwd)<PolymorphicQuerySet [
<TwoWheelDrive: RWD>,
<TwoWheelDrive: FWD>,
<FourWheelDrive: AWD>
]>

Associate the Drive with a CarModel

$ fwd.carmodels.add(s200, c200)
$ fwd.carmodels.all()
<QuerySet [
<CarModel: C200>,
<CarModel: S200>,
<CarModel: S500>
]>

Removing Drive from a CarModel:

$ s500.drive.remove(fwd)
$ s500.drive.all()
<PolymorphicQuerySet [
<TwoWheelDrive: RWD>,
<FourWheelDrive: AWD>
]>

Relation sets can be set:

$ s500.drive.set([awd])
$ s500.drive.all()
<PolymorphicQuerySet [
<FourWheelDrive: AWD>
]>

Relation sets can be cleared:

$ s500.drive.clear()
$ s500.drive.all()
<PolymorphicQuerySet []>

For more information about Polymorphism in Django you can check :

If you want to learn more about Django, do check out the documentation, and make sure to check out our articles!

--

--