Как разработать гибкую модель данных о продукте в Django для различных спецификаций продукта?

В настоящее время я работаю над созданием модели данных о продукте на Django для управления деталями промышленного оборудования. Проблема заключается в том, что некоторые продукты имеют общие спецификации, в то время как другие имеют дополнительные, уникальные спецификации. Фиксирование всех полей в одной модели не представляется возможным из-за изменчивости атрибутов продукта.

Например:

Продукт A и Продукт B разделяют такие атрибуты, как weight, power и dimensions.

Продукт C имеет уникальные спецификации, такие как operating temperature и safety standards, которые применимы не ко всем продуктам.

Каким будет наилучший подход к разработке гибкой и масштабируемой модели данных в Django, которая учитывает:

  • Общие спецификации для нескольких продуктов
  • Дополнительные, уникальные спецификации для определенных продуктов

Вариант 1: Entity-Attribute-Value model

Определите общие поля как поля продукта, используйте модель Entity-Attribute-Value (EAV) [wiki] для тех, которые не являются общими.

Таким образом, вы можете построить Attribute модель, которая по сути является именем (и, возможно, некоторыми другими атрибутами):

class Attribute(models.Model):
    name = models.CharField(max_length=128, unique=True)

    def __str__(self):
        return self.name

и модель AttributeValue, содержащую стоимость каждого продукта, например:

class AttributeValue(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    attribute = models.ForeignKey(Attribute, on_delete=models.CASCADE)
    value = models.FloatField()

    def __str__(self):
        return f'{self.product_id} {self.attribute_id}: {self.value}'

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=('product', 'attribute'),
                name='unique_attributes_per_product',
            )
        ]

Таким образом, линеаризуются значения атрибутов для каждого продукта, но преимущество в том, что вы все еще можете эффективно фильтровать по ним. Например, мы можем извлекать Product продукты с количеством weight меньше 10 (килограммов) с помощью:

Product.objects.filter(
    attributevalue__attribute__name='weight', attributevalue__value__lte=10
)

Если у вас несколько типов значений, думаю, в этом случае имеет смысл прикрепить EAV для каждого типа значения (таким образом, отдельный для строкоподобных данных).

Вариант 2: JSON blob

Другой вариант - добавить JSON-блоб к данным с помощью поля JSONField model [Django-doc]. Преимущество в том, что это позволяет легко сбрасывать в блоб всевозможные данные по каждому товару. Недостатком является то, что фильтрация по JSON-блобам обычно не очень эффективна, а также то, что это не самый компактный способ хранения и получения данных из базы данных: каждый раз, когда вы получаете Product, извлекаются и все атрибуты, но это само по себе не обязательно:

class Product(models.Model):
    # …
    extra_attributes = models.JSONField()
Вернуться на верх