Updating the value of a model variable remotely

Question:

I want to update the value of inventory in ‘Item’ whenever I create a ‘PurchaseItem’ object.

model.py(1):

class PurchaseItem(models.Model):

product = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.PositiveSmallIntegerField()
purchase_price = models.DecimalField(max_digits=6, decimal_places=2)
paid_amount = models.DecimalField(max_digits=6, decimal_places=2)
date_created = models.DateTimeField(auto_now_add=True)

Here, quantity represents no. of items purchased so when I create this object; I want inventory value to be updated here:
model.py(2):

class Item(models.Model):
    title = models.CharField(max_length=100)
    model = models.CharField(max_length=100)
    sku = models.CharField(max_length=100)
    ean = models.CharField(max_length=100)
    price = models.FloatField()
    inventory = models.IntegerField()
Asked By: Sesshōmaru

||

Answers:

you can use signals or:

first of all edit your PurchaseItem model and add related_name to product field:

class PurchaseItem(models.Model):
    product = models.ForeignKey(Item,related_name="purchases", on_delete=models.CASCADE)
    quantity = models.PositiveSmallIntegerField()
    purchase_price = models.DecimalField(max_digits=6, decimal_places=2)
    paid_amount = models.DecimalField(max_digits=6, decimal_places=2)
    date_created = models.DateTimeField(auto_now_add=True)

now when you create a purchase item:

purchase_item = PurchaseItem.objects.create(...)
purchase_item.item.inventory += purchase_item.quantity # or any number you want
purchase_item.item.save()

but try to use singnals.

Answered By: amirhossein amiri

Using Django, three ways come to mind:

  1. Create a signal receiver that’s called whenever a PurchaseItem is created, that signal could call a method that handles updating logic.
  2. Override save() method of PurchaseItem, check if object is being created or updated, then call another method that handles updating logic.
  3. You could also have a view call updating logic, but you might want to keep business out of view as much as possible.

Hope this helps. 🙂

Update1: With signals example

https://docs.djangoproject.com/en/dev/ref/signals/#post-save

@receiver(post_save, sender=PurchaseItem)
def update_inventory(sender, purchase_item, created, **kwargs):
    if not created:
        return
    purchase_item.product.update_inventory(purchase_item.quantity)
Answered By: Alireza Amouzadeh

First of all, i would like to corret the other guy who answered about related_name, it should be done like this:

add a related_name for better querying:

class PurchaseItem(models.Model):

    product = models.ForeignKey(
        Item, on_delete=models.CASCADE, related_name="purchases"
    ) # here
    quantity = models.PositiveSmallIntegerField()
    purchase_price = models.DecimalField(max_digits=6, decimal_places=2)
    paid_amount = models.DecimalField(max_digits=6, decimal_places=2)
    date_created = models.DateTimeField(auto_now_add=True)

Now from an Item instance, you can get all PurchaseItem instances that has "product" as being the Item instance, for example:

foo = Item.objects.get(title="FOO") # getting FOO

foo_purchases = foo.purchases.all() # getting all PurchaseItem objects that has "foo" as being the "product" attribute

But you’l wont need it to create signals… All you need to do is:

from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver

@receiver(post_save, sender=PurchaseItem)
def update_item_inventory_on_create(sender, instance, created, **kwargs):

    """
    Everytime you create a PurchaseItem it will decrease the Item used as "Product" inventory
    based on the PurchaseItem quantity.

    Example: If my Product had 10 samples on inventory, and i create a PurchaseItem with 2 as quantity,
    after this signal is called, my product will now have only 8 samples on inventory.
    """

    if created:
        purchase_item_created = instance
        purchase_item_created.product.inventory -= purchase_item_created.quantity
        purchase_item_created.product.save()

@receiver(post_delete, sender=PurchaseItem)
def update_item_inventory_on_delete(sender, instance, **kwargs):
    """
    Everytime you delete a PurchaseItem it will increase the Item used as "Product" inventory
    based on the PurchaseItem quantity.

    Example: If my Product had 8 samples on inventory, and i have deleted a PurchaseItem with 2 as quantity,
    after this signal is called, my product will now have 10 samples on inventory.
    """

    purchase_item_created = instance
    purchase_item_created.product.inventory += purchase_item_created.quantity
    purchase_item_created.product.save()

Please refer to the documentation for better explanation, i tried my best to make it concise and explained on the signals docstrings.

But with that code, you will be able to decrease item inventory on PurchaseItem create and increase it on PurchaseItem deletion

Answered By: Ives Furtado
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.