Mon article Django se comporte différemment des autres polymorphes J'ai écrit sur le fait que le modèle polymorphe de Django est différent du soi-disant polymorphe lié. Cette fois, j'expliquerai le point "Comment implémenter ** lié polymorphe ** dans Django".
Dans le chapitre Polymorphic Associations du guide Rails, la relation polymorphique est implémentée comme suit.
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
L'objectif est d'implémenter un modèle qui possède les attributs de type ER suivants.
coontent_type
indique quelle table est associée et ʻobject_id` indique quel enregistrement est associé.
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()
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()
#migration
$ python manage.py makemigrations polymorphic_associations
$ python manage.py migrate polymorphic_associations
$ python manage.py shell
#Création de données
>>> 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)>
#L'acquisition des données
>>> 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'
#Confirmation SQL
>>> 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
)'
Vous pouvez voir que les données créées peuvent identifier la table et l'enregistrement par content_type_id
et ʻobject_id. Cela permet à toutes les tables avec des images d'être implémentées rapidement en héritant de ʻImageable
. De plus, en implémentant le traitement d'image dans Imageable, il est possible d'empêcher la logique d'être distribuée à chaque modèle et service.
Ce code source peut être trouvé dans Git.
Recommended Posts