shahab
shahab

Reputation: 323

automatically create a model object when an object of another table is created or updated in django models

I have two models in Django and I want to automatically create an object of History when an object of Food is created or updated and set the food_price attribute of History to the price attribute of the created Food object. My purpose is to have a history of food change price. How can I achieve that?

My models.py is:

class Food(models.Model):
    food_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=30, null=False, blank=False)
    desc = models.TextField(max_length=200)
    price = models.IntegerField(null=False, blank=False)
    f_thumbnail = models.ImageField(upload_to=get_food_t_image_name)
    DDD_data = models.ImageField(upload_to=get_food_d_image_name)
    availability = models.BooleanField(default=True)
    discount = models.IntegerField(default=0)

    def __str__(self):
        return '%s %s %s' % (self.name, self.category_id, self.price)

class History(models.Model):
    id = models.AutoField(primary_key=True)
    food_id = models.IntegerField()
    food_price = models.IntegerField()
    history_date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return '%s %s %s' % (self.id, self.food_id.name, self.food_id.price)

Thanks in advance.

Upvotes: 1

Views: 1321

Answers (1)

seuling
seuling

Reputation: 2966

I think you have two ways.

First, use __save__() method in model.

In django model, (models.Model), there's __save__ method. When model object saves, you can do an additional feature that inherits this method.

For more information, please check official docs save()

Second, use signals

Django supports many signals including django.db.models.signals. It includes pre_save, post_save, and so on. So before(after) saving model object, you can do sth in signals.

Please check official docs signals

I think __save__() method is more fit to your purpose. So your code will be...

class Food(models.Model):
    food_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=30, null=False, blank=False)
    desc = models.TextField(max_length=200)
    price = models.IntegerField(null=False, blank=False)
    f_thumbnail = models.ImageField(upload_to=get_food_t_image_name)
    DDD_data = models.ImageField(upload_to=get_food_d_image_name)
    availability = models.BooleanField(default=True)
    discount = models.IntegerField(default=0)

    def __str__(self):
        return '%s %s %s' % (self.name, self.category_id, self.price)

    def save(self, force_insert=False, force_update=False, *args, **kwargs):
        # you can add this for only existing model object
        if self.pk:
            # You can check if only 'price' field changed
            _original_food = Food.objects.get(id=self.pk)
            if _original_food.price != self.price:
                # do somthing here like saving history...
                History.objects.create(food_id=self.id, food_price=self.price)
                super(Food, self).save(force_insert, force_update, *args, **kwargs)
        super(Food, self).save(force_insert, force_update, *args, **kwargs)

This is just example. You can add & modify your code. I hope it helps you.

Upvotes: 2

Related Questions