15👍
The property is called each time you access product.total_ammount_in_store
, not at the time when the product is created.
Therefore including {{ product.total_ammount_in_store }}
in your template will do the right thing.
By using the property decorator, you can access product.total_ammount_in_store
instead of product.total_ammount_in_store()
if it was an instance method. In the Django template language, this difference is not so apparent, because Django will call the method automatically in the template.
Don’t confuse an instance method with a class method, which is quite different. A class method belongs to your class Product
, not an individual instance product
. You don’t have access to instance variables e.g. self.package
when you call a class method.
3👍
The @property
decorator can be used to implement a getter for your class’ instance variable (in your case it would be self.total_ammount_in_store
). Every time you call some_product.total_ammount_in_store
, the decorated method is executed. It wouldn’t make sense to execute it only when a new object is created – you want to get current amount in store, don’t you?
More reading on @property
is in Python documentation (it’s a Python’s construct, not Django’s):
https://docs.python.org/2/library/functions.html#property
As for class methods, they are something completely different. As the name suggests, they’re tied to classes, not instances. Therefore, no instance is needed to call a class method, but also you can’t use any instance variables in class methods (because they are tied to a particular instance).
To the Django related part of your question…
If you include {{ some_product.total_ammount_in_store }}
in your template, then every time the page is displayed, the total amount in store is obtained from the some_product
instance. Which means that the decorated total_ammount_in_store
getter is called.
If for example the total amount in store isn’t changed during the product’s life, you can calculate the amount in __init__
method and then only return the value. If the total amount can change you can do it as well but you will need to ensure that the amount is re-calculated every time it should be changed – e.g. by calling a method. Like this:
class Product(object):
def __init__(self):
# ...
# other initialization
# ...
self.recalculate_amount()
def recalculate_amount(self):
consignments = self.product.package.consignments
self._total_amount = 0
for consignment in consignments:
self._total_amount += consignment.package_amount
@property
def total_amount(self):
"""Get the current total amount in store."""
return self._total_amount
Then the getter is still called every time you call some_product.total_ammount_in_store
(e.g. in your Django template), but it will not calculate the amount every time – it will use the stored amount instead.
- Can celery,celerybeat and django-celery-beat dynamically add/remove tasks in runtime without restart celerybeat?
- ArrayField missing 1 required positional argument
- Django nested if else in templates