在 Django 模板中过滤反向查找
Filtering a reverse lookup in Django template
我有一个看起来像这样的模型
class Invoice(models.Model):
inv_number = models.CharField(max_length=10, primary_key=True)
customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
inv_date = models.DateField()
class Txn(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.PROTECT)
transaction_date = models.DateField()
reference = models.CharField(max_length=12)
amt = models.IntegerField()
我想在我的模板中显示一个报告,其中列出过滤后的发票,每个发票都有过滤后交易的子列表。
在我看来,我做了以下事情:
invoice_list = Invoice.objects.filter(customer=customer)
我将其传递到我的模板中。在模板中,我执行如下操作:
{% for invoice in invoice_list %}
{{ invoice.inv_number }}, {{ invoice.customer}}, {{ invoice.inv_date }}
{% for txn in invoice.txn_set.all %}
{{ txn.transaction_date }}, {{ txn.reference }}, {{ txn.amt }}
{% endfor %}
{% endfor %}
这非常适合显示每张过滤发票的整个交易列表。问题是,如何在模板中过滤每张发票的交易列表——如果我只想要特定日期范围内的交易或与特定参考匹配的交易怎么办?在将主查询集放入上下文之前,是否可以将过滤器传递给视图中每个发票的 txn_set 查询集,而不将它们转换为列表?
感谢您的任何回复!
建议:在视图中收集发票和交易记录,而不是在模板中。
使用此视图代码,您可以将查询数量减少到 1,因此它比您的代码优化得多(对于每张发票查询 Txn
table):
# build basic query
qs = Txn.objects.select_related('invoice')\
.filter(invoice__customer=customer)\
.order_by('transaction_date')
# add filtering; here is an example, but it could be with date filter as well
reference = request.GET.get('reference', '')
if len(reference) > 0:
qs = qs.filter(reference__icontains=reference)
invoice_dict = {}
for txn in qs:
# add the Invoice if it does not exist yet
if txn.invoice_id not in invoice_dict:
invoice_dict[txn.invoice_id] = {
'invoice': txn.invoice,
'txn_list': [],
}
# add the Txn
invoice_dict[txn.invoice_id]['txn_list'].append(txn)
# sort by Invoice date
invoice_data_list = sorted(
invoice_dict.values(),
key=lambda x: x['invoice'].inv_date)
然后在您的模板中:
{% for elem in invoice_data_list %}
{{ elem.invoice.inv_number }}
{{ elem.invoice.customer}}
{{ elem.invoice.inv_date }}
{% for txn in elem.txn_list %}
{{ txn.transaction_date }}
{{ txn.reference }}
{{ txn.amt }}
{% endfor %}
{% endfor %}
我有一个看起来像这样的模型
class Invoice(models.Model):
inv_number = models.CharField(max_length=10, primary_key=True)
customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
inv_date = models.DateField()
class Txn(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.PROTECT)
transaction_date = models.DateField()
reference = models.CharField(max_length=12)
amt = models.IntegerField()
我想在我的模板中显示一个报告,其中列出过滤后的发票,每个发票都有过滤后交易的子列表。
在我看来,我做了以下事情:
invoice_list = Invoice.objects.filter(customer=customer)
我将其传递到我的模板中。在模板中,我执行如下操作:
{% for invoice in invoice_list %}
{{ invoice.inv_number }}, {{ invoice.customer}}, {{ invoice.inv_date }}
{% for txn in invoice.txn_set.all %}
{{ txn.transaction_date }}, {{ txn.reference }}, {{ txn.amt }}
{% endfor %}
{% endfor %}
这非常适合显示每张过滤发票的整个交易列表。问题是,如何在模板中过滤每张发票的交易列表——如果我只想要特定日期范围内的交易或与特定参考匹配的交易怎么办?在将主查询集放入上下文之前,是否可以将过滤器传递给视图中每个发票的 txn_set 查询集,而不将它们转换为列表?
感谢您的任何回复!
建议:在视图中收集发票和交易记录,而不是在模板中。
使用此视图代码,您可以将查询数量减少到 1,因此它比您的代码优化得多(对于每张发票查询 Txn
table):
# build basic query
qs = Txn.objects.select_related('invoice')\
.filter(invoice__customer=customer)\
.order_by('transaction_date')
# add filtering; here is an example, but it could be with date filter as well
reference = request.GET.get('reference', '')
if len(reference) > 0:
qs = qs.filter(reference__icontains=reference)
invoice_dict = {}
for txn in qs:
# add the Invoice if it does not exist yet
if txn.invoice_id not in invoice_dict:
invoice_dict[txn.invoice_id] = {
'invoice': txn.invoice,
'txn_list': [],
}
# add the Txn
invoice_dict[txn.invoice_id]['txn_list'].append(txn)
# sort by Invoice date
invoice_data_list = sorted(
invoice_dict.values(),
key=lambda x: x['invoice'].inv_date)
然后在您的模板中:
{% for elem in invoice_data_list %}
{{ elem.invoice.inv_number }}
{{ elem.invoice.customer}}
{{ elem.invoice.inv_date }}
{% for txn in elem.txn_list %}
{{ txn.transaction_date }}
{{ txn.reference }}
{{ txn.amt }}
{% endfor %}
{% endfor %}