I already asked a similar question on StackOverflow focused on one aspect, but actually my problem is bigger and I need kind of strategic advice and therefore I think, Django forum is the better place to discuss that.
Actually it’s quite a standard scenario: I have invoices, each with one or many items. Each item has a single net price, a quantity and a tax rate. With that I can calculate the total net price for each item as well as the net price and the gross price for the whole invoice.
(I am talking about several hundreds of invoices per year, not millions and there are very few users, so performance shouldn’t be too high prioritized).
These are the essential parts of my models.py :
from django.db import models
from django.db.models import Sum
class Invoice(models.Model):
@property
def price_net(self):
return # …
@property
def price_gross(self):
return # …
class Item(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE)
quantity = models.DecimalField(blank=False, null=False, max_digits=8, decimal_places=2, default=1)
price_single_net = models.DecimalField(blank=False, null=False, max_digits=8, decimal_places=2)
tax_rate = models.PositiveSmallIntegerField(blank=False, null=False, default=DEFAULT_TAX_RATE)
@property
def price_total_net(self):
return self.quantity * self.price_single_net
The view.py is simple:
class InvoiceDetailView(DetailView):
model = Invoice
In my template invoice_detail.html
, this is already working:
{% for item in invoice.item_set.all %}
{{ item.quantity }} {{ item.price_single_net }} {{ item.price_total_net }}
{% endfor %}
So far so good. What about {{ invoice.price_net }}
and {{ invoice.price_gross }}
? I thought it would be a good idea to define that as a Model method as it adds custom “row-level” functionality to my objects, right?
But how can I calculate these values? The problem is, that price_total_net
also is a Model method and therefore something like
class Item(models.Model):
# …
def price_net(self):
return self.item_set.aggregate(price_net=Sum('price_total_net'))['price_net']
– which works perfectly for the attribute price_single_net
– shows an error: Cannot resolve keyword ‘price_total_net’ into field.
I am stuck at that point. As quite a beginner, I used to pack everything in the view and I am aware that I can aggregate (or annotate?) the data there somehow, but wouldn’t it be better to have a Model method for that?
Is my general approach OK or would you recommend something completely different? Do you have any advice for me?