Модель Django для связи с «контейнером» другой модели нескольких объектов
Извините за странное название темы, но я пытаюсь найти лучший способ создания связи модели с некоторым набором объектов. Допустим, у меня есть несколько моделей:
class Furniture(models.Model):
title = models.CharField()
category = models.ForeignKey(Category)
price = models.PositiveIntegerField()
class Plumbing(models.Model):
title = models.CharField()
....
class Part(models.Model):
title = models.CharField()
code = models.CharField()
Я хочу построить отношения каждого Furniture / Plumbing
экземпляра с некоторым набором Part
экземпляров (например, арматура, винты и т.д.). Первый наиболее очевидный подход - создать поле ManyToMany
в моделях Furniture
и Plumbing
. Но интересно, есть ли другой подход - создать некий «контейнер», чтобы все объекты были связаны между собой. Как известно, в Django нет поля one-to-many
, и я не хочу держать множество полей null
в Part
, если я решу сделать отношения для многих других моделей (не только Furniture
и Plumbing
).
Я знаю, что архитектоника моделей не имеет смысла, так как это унаследованный код, но любые предложения приветствуются.
Вы можете создать «контейнерную» модель, которая связывает модели мебели, сантехники и деталей через отношения «многие-ко-многим». Например:
class ItemContainer(models.Model):
name = models.CharField(max_length=100)
class Furniture(models.Model):
title = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
price = models.PositiveIntegerField()
containers = models.ManyToManyField(ItemContainer)
class Plumbing(models.Model):
title = models.CharField(max_length=100)
containers = models.ManyToManyField(ItemContainer)
class Part(models.Model):
title = models.CharField(max_length=100)
code = models.CharField(max_length=50)
containers = models.ManyToManyField(ItemContainer)
В этой структуре вы создаете модель ItemContainer, которая выступает в качестве контейнера для мебели, сантехники и деталей. Каждый тип элемента может быть связан с несколькими контейнерами, а контейнеры могут содержать связанные детали. Это позволяет избежать добавления нулевых полей и обеспечивает гибкость для будущих отношений.
Вы можете добиться этого, используя комбинацию модели «Контейнер» и GenericRelations
.
Поскольку любой экземпляр Furniture
или Plumbing
может иметь 0 - много соответствующих частей. Этого можно достичь, создав M2M-отношения между Part
и Container
. Затем для связи с Furniture
или Plumbing
можно использовать GenericRelation
from django.db import models
from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Part(models.Model):
title = models.CharField(max_length=255)
code = models.CharField(max_length=50)
class Container(models.Model):
parts = models.ManyToManyField(Part, related_name="containers")
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
class Furniture(models.Model):
title = models.CharField(max_length=255)
category = models.ForeignKey("Category", on_delete=models.CASCADE)
price = models.PositiveIntegerField()
container = GenericRelation(Container)
class Plumbing(models.Model):
title = models.CharField(max_length=255)
container = GenericRelation(Container)
# ========================================
# Usage example
furniture = Furniture.objects.last()
furniture_parts = furniture.container.first().parts.all()
plumbing = Plumbing.objects.last()
plumbing_parts = plumbing.container.first().parts.all()