I am new to Django and Python and I want to do something I used to do 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 each time an Item
is added to SaleDetail
, update SaleDetail.unit_price
with Item.default_price
if SaleDetail
is new or no unit_price
is set.
What I used to do in Java POJOs was to include this logic in the setter method. I've tried using python properties to encapsulate the item
property, but Django updates the field directly under the hood so this would break some automatic functionallity.
I've also tried to subclassing ForeignKey to accept a callback function but I couldn't find a way to call a method on the container class.
I want to do this so I can provide a default for the UI but I don't want to include this logic in the view logic, since conceptually I think this logic should be on the model (Server side)
Other use in this case would be to update totals for each sale detail and sale. I would like to calculate this BEFORE the user decides to save the sale, so save signals would not work.
Thanks!
The "unit price" is a literally a function of two different fields. As such I would tend 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 so:
print(sd.unit_price)
sd.unit_price = 500
sd.save()
See if this works for you. We override the save method and check if there is a pk
. If the pk
is None, we know that the SaleDetail
is new. Then, we see if there is a unit_price
. If there is not a unit_price
, we set it to the 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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With