循环遍历django模板中多个列表的更好方法

时间:2009-11-25 00:44:15

标签: django

我有一些大数据集,我正在循环显示数据表。问题是循环需要花费大量时间,目前还可以,因为这是一个内部工具,但我想改进它。

模特:

class Metric_Data(models.Model):
  metric = models.ForeignKey(Metric)
  count = models.IntegerField()
  start_date = models.DateField()

我正在显示一个表,其中第一列是日期,然后每个后续列是列出该日期计数的指标。像这样:

Dates Metric Metric Metric ...
10/11     10     11     12
11/11     22    100   1000
...      ...    ...    ...

我尝试在视图中循环数据并从列表中创建表并将其传递给模板进行渲染,但是每个指标有几个指标和数千个数据点,这相当慢。我已经切换到模板标签:

def getIndex(parser, token):
  try:
    tag_name, a_list, index = token.split_contents()
  except ValueError:
    raise template.TemplateSyntaxError, "%r tag requires exactly two arguments" % token.contents.split()[0]
  return GetIndexNode(a_list, index)

class GetIndexNode(template.Node):
  def __init__(self, a_list, index):
    self.the_list = template.Variable(a_list)
    self.index = template.Variable(index)

  def render(self, context):
    try:
      the_list = self.the_list.resolve(context)
      i = self.index.resolve(context)
      return the_list[i]
    except template.VariableDoesNotExist:
      return ''

这仍然很慢,这可能是因为这是我第一次写模板标签而且我做错了。

编辑:我在视图中提取数据是这样的:

def show_all(request):
  metrics = Metric.objects.all()
  dates = Metric_Data.objects.all().values_list('start_date',flat=True).distinct().order_by('start_date')

  data = []

  for metric in metrics:
    data.append(Metric_Data.objects.filter(metric=metric).order_by('start_date').values_list('count', flat=True))

  return render_to_response('metric/show_all.html', {'dates': dates,
                                                   'metrics': metrics,
                                                   'data': data})

修改:和模板

<table id="theTable" class="paginate-5">
<thead> 
<tr>
<th>Dates</th>
    {% for metric in metrics %}
        <th>{{ metric.name }}</th>
    {% endfor %}
</tr>
</thead>
<tbody> 
{% for date in dates %}
    <tr>
    <td>{{date}}</td>
    {% for metric in data %}
        <td>{% get_index metric forloop.parentloop.counter0 %}</td>
    {% endfor %}
    </tr>
{% endfor %}
</tbody>

我认为解决此问题的最佳位置可能在模型中,但我不确定如何解决它。为日期创建一个表,并在该表上进行查询?

非常感谢您的想法!

3 个答案:

答案 0 :(得分:1)

我认为您只是对数据进行了严格的分组,因此您最终会在相同的项目上多次循环,从而产生非常差的复杂性。尝试将数据结构与模板中使用的方式非常接近。

例如:

def metric_count_on ( metric, date ):
    return Metric_Data.objects.filter(metric=metric,start_date=date).values_list('count',flat=True)
def show_all(request):
    metrics = Metric.objects.all()
    dates = Metric_Data.objects.all().values_list('start_date',flat=True).distinct().order_by('start_date')
    # generate full report.  now, template only has to loop.
    data = [{'date':date, 'metrics':metric_count_on(date, metric)}
       for (date,metric) in itertools.product(dates,metrics)]
    # ...

然后,在模板中,您基本上可以循环:

{% for row in data %}
    <tr>
    <td>{{ row.date }}</td>
    {% for count in row.metrics %}
      <td>{{ count }}</td>
    {% endfor %}
    </tr>
{% endfor %}

答案 1 :(得分:0)

如果您发现视图速度很慢,则问题通常在数据库中。您确定知道哪些查询会进入数据库吗?您可以做一个小的更改,这将大大减少数据库流量。

答案 2 :(得分:0)

我发现这篇博文似乎暗示了类似的问题。

http://www.xorad.com/blog/?p=1497

在我的所有变量上使用“| safe”会将我的加载时间缩短一半,这至少是......

发布以防万一其他人偶然发现此问题。