Рубрики
Без рубрики

Django Polymorphic – Игра с моделями наследство в Django

Первоначально опубликовано здесь Вдохновлен некоторым вопросом Reddit, я попытался найти наиболее эффективный способ … Помечено с Джанго, Питоном, Программированием, новичком.

первоначально опубликовано здесь

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

Что мы знаем:

  • У нас есть несколько продуктов.
  • Продукты будут иметь какую -то спецификацию.
  • Продукты могут быть разных типов, поэтому спецификации будут разными.
  • Спецификация продукта будет хранить информацию о продукте, компонентах и их спецификации.

Пример.

ПК, который имеет:

  • ОЗУ память 32 ГБ DDR4
  • ЦП (Intel Core i5 6cores 4,5GH)
  • Источник питания (100 Вт)

Ноутбук:

  • ОЗУ память 16 ГБ DDR4
  • ЦП (Intel Core i5 6cores 4,5GH)
  • Камера FaceTime HD 720p

Первое, что я вижу, это то, что модель спецификации может отличаться в каждом типе продукта. Так что, возможно, общепринято для каждого ноутбука, но отличается для ПК.

Еще одна вещь, которую нужно заметить, это то, что некоторые спецификации будут иметь общие компоненты. Посмотрите на процессор выше. Я думаю, что сделать каждый компонент объектом – хорошая идея. Одна модель для процессоров, одна для оперативной памяти и т. Д.

Давайте начнем просто. Модели для компонентов:

class Cpu(models.Model):
    name = models.CharField(max_length=30)
    numberOfCores = models.IntegerField(default=4)
    frequency = models.FloatField(default=4.5)

    def __str__(self):
        return f"{self.name} {self.numberOfCores} - cores  {self.frequency}GH"


class RamMemmory(models.Model):
    quantity = models.IntegerField(default=4)
    type = models.CharField(max_length=10)

    def __str__(self):
        return f"{self.quantity} GB {self.type}"


class PowerSupply(models.Model):
    name = models.CharField(max_length=30)
    power = models.IntegerField(default=100)

    def __str__(self):
        return f"{self.name} {self.power}W"

class Camera(models.Model):
    name = models.CharField(max_length=30)
    resolution = models.IntegerField(default=720)

    def __str__(self):
        return f"{self.name} {self.resolution}p"

Теперь давайте подключим их в спецификации. Наследство – хорошая идея здесь. Одна вещь, которую нужно помнить, это то, что я не могу установить SpectAbStract как абстрактный, потому что абстрактная модель не имеет внешнего ключа. Я оставил реферат во имя, чтобы узнать, что я унаследовал от него позже.

class SpecsAbstract(models.Model):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=100)

    def __str__(self):
        return f"{self.name} - {self.description}"

class PcSpecification(SpecsAbstract):
    cpu = models.ForeignKey(Cpu, on_delete=models.SET_NULL, null=True)
    ram = models.ForeignKey(RamMemmory, on_delete=models.SET_NULL, null=True)
    powerSupply = models.ForeignKey(PowerSupply, on_delete=models.SET_NULL, null=True)


class LaptopSpecification(SpecsAbstract):
    cpu = models.ForeignKey(Cpu, on_delete=models.SET_NULL, null=True)
    ram = models.ForeignKey(RamMemmory, on_delete=models.SET_NULL, null=True)
    camera = models.ForeignKey(Camera, on_delete=models.SET_NULL, null=True)

Подключите все в модели продукта.

class Product(models.Model):
    name = models.CharField(max_length=100)
    spec = models.ForeignKey(SpecsAbstract, on_delete=models.RESTRICT)

    def __str__(self):
        return f"{self.name}"

И это все. Теперь вы можете добавить разные компоненты к различным спецификациям и подключить их к продуктам.

Но вот один улов. Если вы попытаетесь получить экземпляр объекта спецификации из экземпляра продукта, Django вернет базовую модель (тип SpectAbStract).

>>> Product.objects.first( ).spec

Решение для этого – использовать Джанго-полиморфный Анкет Вместо базового класса он вернет дочернюю модель спецификации продукта.

>>> Product.objects.first( ).spec

Чтобы исправить это, просто установите django-polymorphic PIP установить django-polymorphic , добавить его в настройки.py и изменить класс SpecSabStract.

from polymorphic.models import PolymorphicModel

class SpecsAbstract(PolymorphicModel):
    name = models.CharField(max_length=100)
    description = models.CharField(max_length=100)

    def __str__(self):
        return f"{self.name} - {self.description}"

Что еще?

Несколько полезных функций джанго-полиморфных моделей.

  • Запросы

Queryset теперь будет полиморфным. Вместо того, чтобы возвращать связанные экземпляры SpectSabStract, экземпляры детских моделей будут возвращены.

>>> SpecsAbstract.objects.all( )
,
    
    ]>
  • exance_of и not_instance_of

Получите все детские модели экземпляров данного класса или всех остальных без данного класса.

>>> SpecsAbstract.objects.instance_of(PcSpecification)
]>

>>> SpecsAbstract.objects.not_instance_of(PcSpecification)
]>
  • не_полиморфный

В особых случаях, если вы хотите, чтобы ваш запрос действовал как ванильный Django, вы можете использовать не_полиморфный метод.

>>> SpecsAbstract.objects.all( ).non_polymorphic( )
,
    
    ]>

И многое другое. Проверьте док если ты заинтересован.

И еще кое-что! Если хотите, то, что вы только что прочитали, рассмотрите возможность подписаться на мой список рассылки ( внизу этой страницы ). Обещаю не спам. Ваше здоровье! 😉

Оригинал: “https://dev.to/kuba_szw/django-polymorphic-playing-with-models-inheritance-in-django-5e2c”