Как вычесть содержимое IntegerField одной таблицы из другой в Django?

Как это работает: Когда я добавляю товар в таблицу Bouquet, в классе CompositionOfTheBouquetInline я могу выбрать объект из таблицы Flower и выбрать количество цветов.

Например,

  • в таблице Flower находится цветок "Роза", stock = 10
  • .
  • в таблице Bouquet есть букет "Букет роз", stock = 1
  • выберите цветок "Роза" в количестве 5 штук и сохраните, в таблице CompositionOfTheBouquet

Что произойдет:

  • цветок "Роза" теперь сток = 5, в таблице Цветок

Формула:

  • Flower.stock = Flower.stock - (CompositionOfTheBouquet.count * Bouquet.stock)

models.py

class Flower(models.Model):
    title = models.CharField(max_length=100)
    stock = models.PositiveIntegerField(default=0)

class Bouquet(models.Model):
    title = models.CharField(max_length=150)
    stock = models.PositiveIntegerField(default=0)

class CompositionOfTheBouquet(models.Model):
    flower = models.ForeignKey(
        Flower, on_delete=models.PROTECT
    )
    bouquet = models.ForeignKey(
        Bouquet, on_delete=models.PROTECT
    )
    count = models.PositiveIntegerField(default=0)

admin.py

from .models import Flower, Bouquet, CompositionOfTheBouquet


class CompositionOfTheBouquetInline(admin.TabularInline):
    model = CompositionOfTheBouquet

@admin.register(Flower)
class Flower(admin.ModelAdmin):
    pass

@admin.register(Bouquet)
class Bouquet(admin.ModelAdmin):
    inlines = [CompositionOfTheBouquetInline, ]

Что нужно сделать: При добавлении цветка и его количества, нужно удалить это количество цветов и сохранить его в таблице Flower, столбец stock.

Важно: расчеты должны производиться при добавлении букета через панель администратора

Мое предложение - переопределить поведение сохранения модели CompositionOfTheBouquet.

Если это не должно быть поведением по умолчанию при каждом создании/обновлении CompositionOfTheBouquet модели, рассмотрите возможность использования proxy models для переопределения метода save() только на proxy классе.

Этого также можно достичь с помощью сигналов, но, согласно этому антипаттерну, лучше их избегать.

Примечание: предполагая count свойство - количество цветов в одном букете.

class CompositionOfTheBouquet(models.Model):
    flower = models.ForeignKey(
        Flower, on_delete=models.PROTECT
    )
    bouquet = models.ForeignKey(
        Bouquet, on_delete=models.PROTECT
    )
    count = models.PositiveIntegerField(default=0)


    # Override __init__ method to keep track of what changed (saves a trip to DB)
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self._initial_count = self.count


    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        # After saving the `CompositionOfTheBouqet` model, update the `Flower` 
        # model using the formula you provided with a small change. Using the
        # count_diff to update the number of flower only by the changed count.
        # This is needed for update scenarios. Also, when you reduce number
        # of flowers in the composition, the flower stock will increase
        count_diff = self.count - self._initial_count
        if count_dict != 0:  # Only update the flower if count has changed
            self.flower.stock = self.flower.stock - (count_diff * self.bouquet.stock)
            self.flower.save()

PS. - небольшое замечание по поводу логики. Если вы выберете слишком много цветов, вы получите ошибку базы данных при установке отрицательного числа в PositiveIntegerField. Это должно быть обработано некоторой валидацией, я полагаю.

Вернуться на верх