Django: Установка IntegerField после отправки формы

Как увеличить поле "наличие" IntergerField после отправки формы?

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

views.py

def new_product(request):
    if request.method != 'POST':
        # No data submitted, create blank form
        form = ProductForm()
    else:
        # POST data submitted, process the data
        form = ProductForm(data=request.POST)

    if form.is_valid():
        product = form.save(commit=False)
        product.owner = request.user
        #product.product_type.availability += 1    # This didn't work
        #product.product_type.add_product()        # And this didn't work
        product.save()


        return redirect('store')
        
    context = {'form': form}
    return render(request, 'store/new_product.html', context)

models.py

class ProductType(models.Model):
    availability = models.IntegerField(default=0) ## How to increase this on the fly?
    price = models.DecimalField(max_digits=7, decimal_places=2, default=6.99)
    product_type = models.CharField(max_length=200, default="Tier1")
    cores = models.IntegerField(default=1)
    ram = models.IntegerField(default=2)
    disk = models.IntegerField(default=10)

    def __str__(self):
        return self.product_type

    def add_product(self):
        self.availability = self.availability + 1
        print(self.availability)

forms.py

class ProductForm(forms.ModelForm):
    class Meta:
        model = Product
        fields = ['host_name', 'host_password', 'product_type']

Учитывая используемые вами решения, вы можете переопределить метод save().

# models.py

def save(self, *args, **kwargs):
    self.availability += 1
    super().save(*args, **kwargs)

Я бы посоветовал вам использовать сигналы post_save, предоставляемые Django. Сигналы - это отличный способ решения подобных проблем. Когда вы хотите выполнить зависимые действия.
When A happens perform B
When A happens and C is in some state perform B

Вы можете создавать пользовательские сигналы, а если хотите, то можете использовать уже существующие сигналы сохранения Django Model (post_save, pre_save и т.д.)


This is how you implement custom signals
import django.dispatch
product_save_signal = django.dispatch.Signal()

You can emit these signals from anywhere you want. Suppose you want to emit this on Product Model Form save. In your case this can go into your new_product function.

def save(self, *args, **kwargs): # signature of save for the class you are overriding
    super().save(*args, **kwargs)
    pizza_done.send(sender=<pass_your_sender_here>, <pass other data as kwargs here>)

How to use this signal

@receiver(product_save_signal)
def action_after_product_save(sender, task_id, **kwargs):
    product_type_instance = Product.objects.filter(<some_query>).first()
    product_type_instance.availability = F('availability') + 1
    product_type_instance.save()

Note: You should always use F('availability') + 1 i.e F queries to perform increments and similar operation to ensure Django handles race conditions.


Хотя я и узнал кое-что новое, пробуя идеи из ваших ответов, решение оказалось намного проще, чем я думал.

Ответом на мой профлемму было использование F('availability') + 1, а не availability += 1, а затем обновление ProductType из модели Product.

Выглядит это следующим образом:

models.py

class ProductType(models.Model):
    availability = models.IntegerField(default=0)
    price = models.DecimalField(max_digits=7, decimal_places=2, default=6.99)
    product_type = models.CharField(max_length=200, default="Tier1")
    cores = models.IntegerField(default=1)
    ram = models.IntegerField(default=2)
    disk = models.IntegerField(default=10)

    def __str__(self):
        return self.product_type

    def update(self, *args, **kwargs):
        self.availability = F('availability') + 1
        super().save(*args, **kwargs)

    def check_availability(self):
        if self.availability > 0:
            return True
        else:
            return False


class Product(models.Model):
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    host_name = models.CharField(max_length=200, default="")
    host_password = models.CharField(max_length=200, default="")
    product_type = models.ForeignKey(ProductType, null=True, blank=True, on_delete=models.CASCADE)

    def __str__(self):
        return self.host_name

    def save(self, *args, **kwargs):
        self.product_type.update()
        super().save(*args, **kwargs)
Вернуться на верх