Модель 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()
Вернуться на верх