I would like to get all items belonging to an invoice and show them to a template without success. What i have done so far is the following:
I have two models:
class Invoice(models.Model):
PAYMENT_OPTIONS = (
('CASH', _('CASH')),
('DEPOSIT', _('DEPOSIT')),
('CARD', _('CARD')),
)
INVOICE_TYPE = (
('Service', _('Service')),
)
invoice_number = models.CharField(max_length=7, unique=True, default='INV4898')
invoice_user = models.ForeignKey(Account, on_delete=models.CASCADE)
invoice_type = models.CharField(max_length=30, choices=INVOICE_TYPE, default='Service')
payment_option = models.CharField(max_length=30, choices=PAYMENT_OPTIONS)
invoice_name = models.CharField(max_length=30, null=True, blank=True)
vat = models.CharField(max_length=9, blank=True, null=True)
gross_amount = models.DecimalField(max_digits=6, decimal_places=2)
vat_amount = models.DecimalField(max_digits=6, decimal_places=2)
net_amount = models.DecimalField(max_digits=6, decimal_places=2)
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.invoice_user.first_name} {self.invoice_user.last_name} - {self.invoice_number}"
class Item(models.Model):
invoice = models.ForeignKey(Invoice, related_name='items', on_delete=models.CASCADE)
title = models.CharField(max_length=255)
quantity = models.IntegerField(default=1)
unit_price = models.DecimalField(max_digits=6, decimal_places=2, default=Decimal('0.00'))
net_amount = models.DecimalField(max_digits=6, decimal_places=2, default=Decimal('0.00'))
vat_rate = models.CharField(max_length=10, default=0)
discount = models.DecimalField(max_digits=6, decimal_places=2, default=Decimal('0.00'))
is_paid = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.invoice.invoice_number}"
In the views.py i have a list view like, in which i'm trying to get a list of all invoices based on invoice_number and then match each invoice_number to an invoice in items. However using below code first pring brings all invoice_number(s) and second print brings all items for all invoices, not items per invoice.
def list_invoices(request, userprofile_id):
user_profile = get_object_or_404(Account, pk=userprofile_id)
all_invoices =Invoice.objects.filter(invoice_user=user_profile)
invoice_number = Invoice.objects.values_list('invoice_number')
print(invoice_number)
item_invoice = Item.objects.filter(invoice__invoice_number__in=invoice_number)
print(item_invoice)
context = {
'all_invoices': all_invoices,
'user_profile': user_profile,
'item_invoice': item_invoice,
}
return render(request, 'invoices/list-invoices.html', context)
I would appreciate any help.
CodePudding user response:
You do not need to fetch the Item
s not the invoice_number
of the Invoice
. You only need to pass the invoices of the user_profile
, and it might be better to also prefetch the Item
s:
def list_invoices(request, userprofile_id):
user_profile = get_object_or_404(Account, pk=userprofile_id)
all_invoices = Invoice.objects.filter(
invoice_user=user_profile
).prefetch_related('items')
context = {
'all_invoices': all_invoices,
'user_profile': user_profile
}
return render(request, 'invoices/list-invoices.html', context)
then in the template, you can access the .items
, so:
<ul> {% for invoice in all_invoices %} <li> {{ invoice.invoice_number }}</li> <ul> {% for item in invoice.items.all %} <li>{{ item.quantity }} {{ item.title }}</li> {% endfor %} </ul> {% endfor %} </ul>