创建一个视图/模板,允许用户选择的日期过滤,包括子对象的总和?
Posted
技术标签:
【中文标题】创建一个视图/模板,允许用户选择的日期过滤,包括子对象的总和?【英文标题】:Create a view/template that allows for user selected date filtering that includes Sum totals for child objects? 【发布时间】:2014-06-18 13:07:05 【问题描述】:我有两个模型:
class User(models.Model):
name = models.CharField(max_length=50, blank=False)
class Transaction(models.Model):
user = models.ForeignKey(User, blank=False)
description = models.CharField(max_length=50, blank=False)
total = models.DecimalField(default=0, decimal_places=2)
date = models.DateField(blank=True)
year = models.CharField(max_length=4)
type = models.CharField(max_length=1, db_index=True, choices=(
('C', 'Cash'),
('V', 'Visa'),
('A', 'Amex'),
))
我正在尝试提出一个视图/模板,这将允许我显示一个 html 表格/报告,其中显示每个用户以及每种交易类型的总数。即
User Visa Cash Amex Total
User1 $50 $75 $100 $225
第一个报告看起来很简单,一个返回用户查询集的列表报告,在用户模型中,我创建了单独的函数来返回每种交易类型的总数(作为反向 ForeignKey),如下所示:
def value_visa(self):
value = self.transaction_set.filter(user=self,type__in=('Visa')).aggregate(Sum('total'))
return value['total__sum']
def value_all(self):
value = self.transaction_set.filter(user=self).aggregate(Sum('total'))
return value['total__sum']
我知道这可能不是一个理想的解决方案,但它确实有效。
但是,现在我正在尝试按日期(或按字符串年份字段)过滤汇总表中包含的事务,但我不知道该怎么做。我设计的函数方法需要一个参数来将日期限制为特定日期(不能在模板中提供),或者如果我为交易预取相关(目前没有开发补丁是不可能的),我无论如何都无法在模板中求和,也无法弄清楚如何返回包含用户和总和的查询集。日期既可以在 URL 中提供,也可以作为用户在表单上的选择,并不重要。
有什么想法吗?我已经用这个把头发拉了一段时间了!
提前感谢您的任何想法!
编辑: 我在视图的 get_context_data 方法中解决了这个问题:
users = User.objects.annotate(transactions=Count('transaction')).exclude(transactions=0).order_by('name')
for u in users:
totals = Transaction.objects.filter(user=u,year='2012').values('type').annotate(total=Sum('total'))
有了这个总数就变成了每个不同类型值的总数的字典 - 所以这很完美。但是,我不确定如何将这两者都放到模板中 - users 是一个 QuerySet 和一个总数数组(因为用户中的每个项目都会有一个,包括一些没有值的项目)。
【问题讨论】:
我想这与在系统中有发票然后想要打印带有小计(根据与发票关联的项目计算)或列在发票。 因为您不应该在模板中进行求和(可能是 SQL 优化的大量数据)。使用 AJAX 或单独的页面。找到一种方法将所需的日期过滤器提供到您的过滤器函数中并重新呈现页面。你在正确的轨道上!transaction_set.filter(date__gte=datetime(request.GET.get('minimum-date')))
等
知道我从哪里开始使用 AJAX 吗?我的 HTML 技能回到了 90 年代后期! :) 我认为最好让 SQL 服务器以明智的方式进行求和。我看到的最多的是大约 25,000 行要排序,在一个相当低的利用率页面上。我正在考虑实现缓存,以便每次都重新加载查询。
AJAX 通过 jQuery 归结为:$.ajax(url: 'load_some_url_in_full', success: function(response) alert(response) ....
响应可以是完整的 HTML,替换整个页面、一些片段、JSON。为什么不从更简单的问题开始并重新加载页面呢? /filter-by-date-range/2014-1-1/2014-1-20/
或 ?start-date=2014-1-1&end-date=...
我对 ajax 评论的看法是,它只是一个正常的页面加载,您可以通过 js 在成功回调中执行任何操作。你做什么取决于你.. 通过 JSON 发送 2 小段数据?整个html?
【参考方案1】:
只是为了关闭这个循环,我最终在视图中执行了几个单独的查询,然后通过一个 for 循环将它们合并为一个 dict 并将其传递给模板。有点难看……但它起作用了。
【讨论】:
以上是关于创建一个视图/模板,允许用户选择的日期过滤,包括子对象的总和?的主要内容,如果未能解决你的问题,请参考以下文章