[PYTHON] Django Polymorphic Associations Tutorial

Introduction

My article Django behaves differently from other Polymorphic I wrote about how Django's Polymorphic Model is different from the so-called polymorphic model. This time, I'll explain how to implement ** polymorphic related ** in Django.

environment

goal

In the Rails Guide's Polymorphic Associations chapter, polymorphic related is implemented as follows.

class Picture < ApplicationRecord
  belongs_to :imageable, polymorphic: true
end
 
class Employee < ApplicationRecord
  has_many :pictures, as: :imageable
end
 
class Product < ApplicationRecord
  has_many :pictures, as: :imageable
end

The goal is to implement a Model that has the following ER-like attributes.

imageable.png

coontent_type indicates which table is associated and ʻobject_id` indicates which record is associated.

Implementation

Modeling

from django.db import models
from django.contrib.contenttypes.models import ContentType


class Picture(models.Model):
    object_id = models.IntegerField(db_index=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    file_name = models.CharField()


class Employee(models.Model):
    name = models.CharField()
    email = models.EmailField()


class Product(models.Model):
    name = models.CharField()
    price = models.IntegerField()

Implementation of Imageable class

from django.db import models
from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey
from django.contrib.contenttypes.models import ContentType


class Picture(models.Model):
    object_id = models.IntegerField(db_index=True)
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    file_name = models.CharField(max_length=256)
    content_object = GenericForeignKey('content_type', 'object_id')


class Imageable(models.Model):
    class Meta:
        abstract = True

    pictures = GenericRelation(Picture)


class Employee(Imageable):
    name = models.CharField(max_length=256)
    email = models.EmailField()


class Product(Imageable):
    name = models.CharField(max_length=256)
    price = models.IntegerField()

Operation check

#migration
$ python manage.py makemigrations polymorphic_associations
$ python manage.py migrate polymorphic_associations
$ python manage.py shell


#Data creation
>>> from polymorphic_associations.models import Employee, Product
>>>
>>> employee = Employee(name='John', email='[email protected]')
>>> employee.save()
>>> employee.pictures.create(file_name='employee.jpg')
<Picture: Picture object (1)>
>>>
>>> product = Product(name='Desk', price=1000)
>>> product.save()
>>> product.pictures.create(file_name='product.jpg')
<Picture: Picture object (2)>


#Data acquisition
>>> employee.pictures.all()
<QuerySet [<Picture: Picture object (1)>]>
>>> employee.pictures.first().file_name
'employee.jpg'
>>>
>>> product.pictures.all()
<QuerySet [<Picture: Picture object (2)>]>
>>> product.pictures.first().file_name
'product.jpg'


#SQL confirmation
>>> str(employee.pictures.all().query)
'SELECT
    "polymorphic_associations_picture"."id",
    "polymorphic_associations_picture"."object_id",
    "polymorphic_associations_picture"."content_type_id",
    "polymorphic_associations_picture"."file_name"
FROM
    "polymorphic_associations_picture"
WHERE
    (
        "polymorphic_associations_picture"."content_type_id" = 2
    AND "polymorphic_associations_picture"."object_id" = 1
    )'
>>>
>>> str(product.pictures.all().query)
'SELECT
    "polymorphic_associations_picture"."id",
    "polymorphic_associations_picture"."object_id",
    "polymorphic_associations_picture"."content_type_id",
    "polymorphic_associations_picture"."file_name"
FROM
    "polymorphic_associations_picture"
WHERE
    (
        "polymorphic_associations_picture"."content_type_id" = 3
    AND "polymorphic_associations_picture"."object_id" = 1
    )'

You can see that the created data can identify the table and record by content_type_id and ʻobject_id. This allows all tables with images to be implemented quickly by inheriting ʻImageable. Also, by implementing image-related processing in Imageable, it is possible to prevent logic from being distributed to each model and service. This source code is posted on Git.

reference

Recommended Posts

Django Polymorphic Associations Tutorial
Python Django Tutorial (5)
Python Django Tutorial (2)
django tutorial memo
Python Django Tutorial (8)
Python Django Tutorial (6)
Start Django Tutorial 1
Python Django Tutorial (7)
Python Django Tutorial (1)
Python Django tutorial tutorial
Python Django Tutorial (3)
Python Django Tutorial (4)
Python Django tutorial summary
django oscar simple tutorial
Django Girls Tutorial Note
Get started with Django! ~ Tutorial ⑤ ~
Get started with Django! ~ Tutorial ④ ~
Get started with Django! ~ Tutorial ⑥ ~
Python Django Tutorial Cheat Sheet
Django
Django Girls Tutorial Summary First Half
Stumble when doing the django 1.7 tutorial
Deploy the Django tutorial to IIS ①
Django Crispy Tutorial (Environment Building on Mac)
Django tutorial summary for beginners by beginners ③ (View)
Django Tutorial (Blog App Creation) ⑤ --Article Creation Function
Django Foreign Key Tutorial Ends in 10 Minutes
Django Tutorial (Blog App Creation) ④ --Unit Test
Django tutorial summary for beginners by beginners ⑤ (test)