Django - update model field based on another field

I am new to Django and Python and I want to do what I have done very often in Java EE.

Consider the following model (only relevant classes):

class Item(models.Model):
    name = models.CharField(max_length=40)
    default_price = models.DecimalField(max_digits=6, decimal_places=2, default=50)

    def __unicode__(self):
        return self.name


class SaleDetail(models.Model):
    item = models.ForeignKey(Item)
    deposit = models.ForeignKey(Deposit)
    quantity = models.PositiveIntegerField()
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)
    sale = models.ForeignKey(Sale)

    def item_updated(self, value):
        if self.unit_price == None:
            self.unit_price = value

      

What I want to do is that every time it is Item

added Item

it is updated SaleDetail.unit_price

with Item.default_price

if SaleDetail

is new or not unit_price

.

What I was doing in Java POJO was to include this logic in the setter method. I tried using python properties to encapsulate the property Item

, but Django updates the field directly under the hood, so this breaks some of the automatic functionality.

I also tried to subclass ForeignKey to accept a callback function, but couldn't find a way to call the method in the container class.

I want to do this so that I can provide a default value for the UI, but I do not want to include this logic in the presentation logic as conceptually I think this logic should be on the model (server side)

Another use in this case would be to update totals for each sale and sale detail. I would like to calculate this before the user decides to save the sell, so there is no way to save the signals.

Thank!

+3


source to share


2 answers


The "unit price" is literally a function of two different fields. So I would like to write it like this:

class Item(models.Model):
    name = models.CharField(max_length=40)
    default_price = models.DecimalField(max_digits=6, decimal_places=2, default=50)

    def __unicode__(self):
        return self.name

class SaleDetail(models.Model):
    item = models.ForeignKey(Item)
    deposit = models.ForeignKey(Deposit)
    quantity = models.PositiveIntegerField()
    entered_unit_price = models.DecimalField(max_digits=6, decimal_places=2, default=None)
    sale = models.ForeignKey(Sale)

    @property
    def unit_price(self, value):
        if self.entered_unit_price is None:
            return self.item.default_price
        else:
            return self.entered_unit_price

    @unit_price.setter
    def unit_price(self, value):
        self.entered_unit_price = value

      



Then use it like this:

print(sd.unit_price)
sd.unit_price = 500 
sd.save()

      

+1


source


See if this works for you. We override the save method and check if there is pk

. If pk

- None, we know what SaleDetail

is new. Then we see if it exists unit_price

. If not unit_price

, we set it to Item.default_price

.



class Item(models.Model):
    name = models.CharField(max_length=40)
    default_price = models.DecimalField(max_digits=6, decimal_places=2, default=50)

    def __unicode__(self):
        return self.name


class SaleDetail(models.Model):
    item = models.ForeignKey(Item)
    deposit = models.ForeignKey(Deposit)
    quantity = models.PositiveIntegerField()
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)
    sale = models.ForeignKey(Sale)

    def save(self, *args, **kwargs):
        # Make sure this is the first save (pk should be None) and there is no unit_price set
        if self.pk is None and not self.unit_price:
            self.unit_price = self.item.default_price
        elif not self.unit_price:
            self.unit_price = self.item.default_price

        # Call the original save method
        super(SaleDetail, self).save(*args, **kwargs)

      

+2


source







All Articles