13


I have a problem to set a default field value. What I want to do?
I want that price in class Packages be a default value of priceNoTax in class Bill. As you can see, all three classes are logically connected.
Example: Account 1 has a package with id 1. Price of this package is 100. Default value of priceNoTax for Account 1 is 100.

How to do that? I am relative new at this, so I need help.

models.py

class Packages(models.Model):
     #other fields
     price = models.IntegerField(validators=[MinValueValidator(1)], verbose_name="Price of package")

class Account(models.Model):
     startDate = models.DateField(verbose_name="Start date")
     finishDate = models.DateField(verbose_name="Finish date")
     idPackage = models.ForeignKey(Packages, on_delete=models.CASCADE, verbose_name="Package")

class Bill(models.Model):
     date = models.DateField(default=datetime.now())
     tax = models.FloatField(default=0.20)
     priceNoTax = models.IntegerField()
     priceTax = models.FloatField(default=priceNoTax+(priceNoTax*tax))
     idAccount = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name="Account")

     def __str__(self):
         return self.date

Thanks a lot!!!

notGenius
  • 139
  • 1
  • 8
  • How are you getting the information into the model? Are you using an admin page or passing it in from another location? There are several ways I can think to do this, but none that specifically set the default attribute to the value from another model. – Matthew Dumas Jan 11 '18 at 20:02
  • You don't need the fields `priceNoTax` and `priceTax` for me as they are *logically connected already*. You can just query from `Bill` class if you want to access prices as `Bill.objects.filter(idAccount__idPackage__price)`. Less duplicate variables. – Lord Salforis Jan 12 '18 at 08:57

3 Answers3

9

perhaps add this to your Bill class?

def save(self, *args, **kwargs):
    if self.priceNoTax is None:
        self.priceNoTax = self.idAccount.idPackage.price
    super(Bill, self).save(*args, **kwargs)
Chris Curvey
  • 9,738
  • 10
  • 48
  • 70
8

Why do you need it to be a field? Do you see a reason where someone would want to change the total price without changing the price and tax to the corresponding values? If it doesn't really need to be a field, you can just make it a method.

class Bill(models.Model):
     date = models.DateField(default=datetime.now())
     tax = models.FloatField(default=0.20)
     priceNoTax = models.IntegerField()
     idAccount = models.ForeignKey(Account, on_delete=models.CASCADE, verbose_name="Account")

     def priceTax(self):
       return self.priceNoTax + (self.priceNoTax*self.tax)

     def __str__(self):
         return self.date

You can still use it the same way in templates with {{ bill.priceTax }}. In code you would need to use bill.priceTax().

This way, the price with tax should stay up-to-date no matter how the tax or price without tax changes.

You can also use @property decorator to avoid having to call it as a function in code.

@property
def priceTax(self):
   return self.priceNoTax + (self.priceNoTax*self.tax)

For more see https://docs.djangoproject.com/en/2.0/topics/db/models/#model-methods

kichik
  • 33,220
  • 7
  • 94
  • 114
  • 2
    10 years later... One problem with this approach is that `priceTax` is not accessible using `models.F()` expression. – keepAlive Jun 14 '18 at 12:02
  • 1
    If you're worried about that, you can add it to the queryset https://stackoverflow.com/a/42491803/492773. That still requires no db changes, so no huge migrations to make and no huge problems 10 years later. – kichik Jan 04 '22 at 13:42
  • Sorry for the "10 years later"... I don't know how I did, but it seems I just misread the dates... Indeed, nothing was more than 2 years old at that time ... Even if this is going to be true faster than we think given how the time flies.. ~6 years already.... That being written, happy new year ! – keepAlive Jan 04 '22 at 14:54
-2

@kichik answered how to display the default value using template tag, and I recommend to implement auto-calculation by javascript.

Of course, you will have to validate user input or implement save() method as @Chris Curvey said.

pincoin
  • 665
  • 5
  • 19
  • Displaying the information is not the problem. https://docs.djangoproject.com/en/2.0/ref/models/fields/#default This seems to be the right answer. – wm3ndez Jan 13 '18 at 18:46