Django 模板的摘要标签

发布于 2024-09-28 22:13:54 字数 1448 浏览 1 评论 0原文

有时我必须使用 Django 编写一些简单的总结报告。

首先,我尝试使用 Django ORM 聚合和交错结果,但它可能会变得有点混乱,而且我失去了所有 ORM 惰性 - 只是感觉不对。

最近,我编写了一个通用迭代器类,可以对数据集进行分组/汇总。在视图中,它的工作原理如下:

s_data = MyIterator(dataset, group_by='division', \
                                   sum_fields=[ 'sales', 'travel_expenses'])

在模板中,它的工作原理如下:

{% for g, reg in s_data %}
    {% if g.group_changed %}
        <tr><!-- group summary inside the loop --> 
            <td colspan="5">{{ g.group }} Division</td>
            <td>{{ g.group_summary.sales }}</td>
            <td>{{ g.group_summary.travel_expenses }}</td>
        </tr>
    {% endif %}
    <tr><!-- detail report lines -->
        <td>{{ reg.field }}<td>
        <td>{{ reg.other_field_and_so_on }}<td>
        ...
    </tr>
{% endfor %}
<tr><!-- last group summary -->
    <td colspan="5">{{ s_data.group }} Division</td>
    <td>{{ s_data.group_summary.sales }}</td>
    <td>{{ s_data.group_summary.travel_expenses }}</td>
</tr>
<tr>
    <td colspan="5">Total</td>
    <td>{{ s_data.summary.sales }}</td>
    <td>{{ s_data.travel_expenses }}</td>
</tr>

我认为它比我以前的方法优雅得多,但必须重复最后一个组摘要的代码违反了 DRY 原则。

我看过“杰拉尔多报道”,但它不是“一见钟情”。

为什么没有组/摘要模板标签,我应该写一个吗?

From time to time I have to write some simple summarized reports using Django.

First I tried using Django ORM aggregates and interleaving results, but it can get a bit messy and I loose all the ORM laziness - just doesn't feels right.

Lately I wrote a generic iterator class that can group/summarize a dataset. In the view it works like:

s_data = MyIterator(dataset, group_by='division', \
                                   sum_fields=[ 'sales', 'travel_expenses'])

In the template it works like:

{% for g, reg in s_data %}
    {% if g.group_changed %}
        <tr><!-- group summary inside the loop --> 
            <td colspan="5">{{ g.group }} Division</td>
            <td>{{ g.group_summary.sales }}</td>
            <td>{{ g.group_summary.travel_expenses }}</td>
        </tr>
    {% endif %}
    <tr><!-- detail report lines -->
        <td>{{ reg.field }}<td>
        <td>{{ reg.other_field_and_so_on }}<td>
        ...
    </tr>
{% endfor %}
<tr><!-- last group summary -->
    <td colspan="5">{{ s_data.group }} Division</td>
    <td>{{ s_data.group_summary.sales }}</td>
    <td>{{ s_data.group_summary.travel_expenses }}</td>
</tr>
<tr>
    <td colspan="5">Total</td>
    <td>{{ s_data.summary.sales }}</td>
    <td>{{ s_data.travel_expenses }}</td>
</tr>

I think it is a lot more elegant than my previous approach but having to repeat the code for the last group summary violates the DRY principle.

I had a look at "Geraldo reporting" but it was not "love at the first sight".

Why there is no group/summary template tag, should I write one?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

软甜啾 2024-10-05 22:13:54

我可能错过了一些就在我面前的东西,但是为什么你有循环之外的最后一组?

I'm probably missing something right in front of my face, but why do you have the last group outside the loop?

怪我太投入 2024-10-05 22:13:54

我发现,它可以用迭代器来完成,不需要模板标签。诀窍是延迟迭代一个周期。

class GroupSummaryIterator(object):
    """GroupSummaryIterator(iterable, group_by, field_list)

- Provides simple one level group/general summary for data iterables.
- Suports both key and object based records
- Assumes data is previously ordered by "group_by" property *before* use

Parameters:
===========
  iterable: iterable data
  group_by: property or key name to group by
field_list: list of fileds do sum

Example:
======
data =  [{'label': 'a', 'field_x': 1, 'field_c': 2},
         {'label': 'a', 'field_x': 3, 'field_c': 4},
         {'label': 'b', 'field_x': 1, 'field_c': 2},
         {'label': 'c', 'field_x': 5, 'field_c': 6},
         {'label': 'c', 'field_x': 1, 'field_c': 2}]

s = GroupSummaryIterator(data, 'label', ['field_x', 'field_c'])
for x,y in s:
     print y
     if x['group_changed']:
         print x['group'], 'summary:', x['group_summary']
print 'general summary:', s.summary

    """
    def __init__(self, iterable, group_by, field_list):
        self.iterable = iterable
        self.group_by = group_by
        self.field_list = field_list
    def _a(self, obj, key):
        """Get property or key value"""
        if isinstance(key, basestring) and hasattr(obj, key):
            return getattr(obj, key)
        try:
            return obj[key]
        except:
            return None
    def _sum(self, item):
        if self.group_changed:
            self.cur_summary = dict()
        for field in self.field_list:
            value = self._a(item, field)
            if not value:
                value = 0.0
            else:
                value = float(value)
            if self.summary.has_key(field):
                self.summary[field] += value
            else:
                self.summary[field] = value
            if self.cur_summary.has_key(field):
                self.cur_summary[field] += value
            else:
                self.cur_summary[field] = value
    def _retval(self, item, summary):
        """If each item from the source iterable is itself an iterable, merge
        everything so you can do "for summ, a, b in i" where you would have
        done "for a, b in i" without this object."""
        if isinstance(item, dict):
            retval = (item,)
        else:
            try:
                retval = tuple(item)
            except:
                retval = (item,)
        return (dict(group_changed=self.group_changed, group=self.group, group_summary=summary),) + retval
    def __iter__(self):
        self.cur_group = None
        self.group = None
        self.finished = False
        self.group_changed = False
        self.cur_item = None
        self.last_item = None
        self.summary = dict()
        self.group_summary = dict()
        self.cur_summary = dict()
        for item in self.iterable:
            self.group = self.cur_group
            self.group_summary = self.cur_summary
            self.cur_group = self._a(item, self.group_by)
            self.group_changed = self.group and self.cur_group != self.group
            self.last_item = self.cur_item
            self.cur_item = item
            self._sum(item)
            if self.last_item is None:
                continue
            yield self._retval(self.last_item, self.group_summary)
        if self.cur_item:
            self.group_changed = True
            yield self._retval(self.cur_item, self.group_summary)

I figured it out, it can be done with iterators, no need for a template tag. The trick is to delay iteration one cycle.

class GroupSummaryIterator(object):
    """GroupSummaryIterator(iterable, group_by, field_list)

- Provides simple one level group/general summary for data iterables.
- Suports both key and object based records
- Assumes data is previously ordered by "group_by" property *before* use

Parameters:
===========
  iterable: iterable data
  group_by: property or key name to group by
field_list: list of fileds do sum

Example:
======
data =  [{'label': 'a', 'field_x': 1, 'field_c': 2},
         {'label': 'a', 'field_x': 3, 'field_c': 4},
         {'label': 'b', 'field_x': 1, 'field_c': 2},
         {'label': 'c', 'field_x': 5, 'field_c': 6},
         {'label': 'c', 'field_x': 1, 'field_c': 2}]

s = GroupSummaryIterator(data, 'label', ['field_x', 'field_c'])
for x,y in s:
     print y
     if x['group_changed']:
         print x['group'], 'summary:', x['group_summary']
print 'general summary:', s.summary

    """
    def __init__(self, iterable, group_by, field_list):
        self.iterable = iterable
        self.group_by = group_by
        self.field_list = field_list
    def _a(self, obj, key):
        """Get property or key value"""
        if isinstance(key, basestring) and hasattr(obj, key):
            return getattr(obj, key)
        try:
            return obj[key]
        except:
            return None
    def _sum(self, item):
        if self.group_changed:
            self.cur_summary = dict()
        for field in self.field_list:
            value = self._a(item, field)
            if not value:
                value = 0.0
            else:
                value = float(value)
            if self.summary.has_key(field):
                self.summary[field] += value
            else:
                self.summary[field] = value
            if self.cur_summary.has_key(field):
                self.cur_summary[field] += value
            else:
                self.cur_summary[field] = value
    def _retval(self, item, summary):
        """If each item from the source iterable is itself an iterable, merge
        everything so you can do "for summ, a, b in i" where you would have
        done "for a, b in i" without this object."""
        if isinstance(item, dict):
            retval = (item,)
        else:
            try:
                retval = tuple(item)
            except:
                retval = (item,)
        return (dict(group_changed=self.group_changed, group=self.group, group_summary=summary),) + retval
    def __iter__(self):
        self.cur_group = None
        self.group = None
        self.finished = False
        self.group_changed = False
        self.cur_item = None
        self.last_item = None
        self.summary = dict()
        self.group_summary = dict()
        self.cur_summary = dict()
        for item in self.iterable:
            self.group = self.cur_group
            self.group_summary = self.cur_summary
            self.cur_group = self._a(item, self.group_by)
            self.group_changed = self.group and self.cur_group != self.group
            self.last_item = self.cur_item
            self.cur_item = item
            self._sum(item)
            if self.last_item is None:
                continue
            yield self._retval(self.last_item, self.group_summary)
        if self.cur_item:
            self.group_changed = True
            yield self._retval(self.cur_item, self.group_summary)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文