如何在Django中向视图传递大量参数?

4

我对Django非常新,并且正在尝试构建一个应用程序,以表格和图表的形式呈现我的数据。到目前为止,我的学习过程一直非常顺利,但现在我有点卡住了。

我的页面视图从数据库中检索大量数据并将其放入上下文中。然后模板生成不同的HTML表格。到此为止一切顺利。
现在我想在模板中添加不同的图表。我通过定义<img src=".../>标签来完成这个任务。Matplotlib图表是在我的图表视图中生成并返回的:

response=HttpResponse(content_type='image/png')
canvas.print_png(response)
return response

现在我有不同的问题:

  1. 从数据库中检索数据两次。一次在页面视图中呈现表格,另一次在图表视图中制作图表。传递数据到图表视图的最佳方式是什么?
  2. 我需要很多不同数据集的图表。我可以为每个图表创建一个图表视图,但可能有更好的方法。如何将不同的数据集名称传递给图表视图?有些图表有20个数据集,所以我不认为通过url传递这些数据集参数(例如:<imgm src="chart/dataset1/dataset2/.../dataset20/chart.png />)是正确的方法。
    有什么建议?
2个回答

6
由于页面视图和图表视图是分开的HTTP请求,因此您无法将数据从页面视图传递到图表视图。您有几个选择:
  1. 在图表的URL中传递所有数据。这听起来可能很疯狂,但这正是Google Charts所做的:http://code.google.com/apis/chart/docs/making_charts.html
  2. 将数据存储在会话中。页面视图将数据放入会话中,而图表视图将使用它创建图表。
  3. 在memcache中缓存您的数据库查询。由于页面和图表都将引用相同的查询,因此您很可能会命中缓存。这是一个不错的解决方案,因为即使没有先呈现页面,您的图表仍将工作。
  4. 只需再次查询数据库。您的DBMS可能具有良好的缓存,性能可能并非您想象的那样差。
对于您的第二个问题,在URL中使用20个单词似乎并不是什么大问题。当然,您可以找到一些数据集选择的模式,以便您不需要每次都指定它们,但如果需要,只需制作长URL即可。

感谢您的回答,Ned。 第一点:那个方法可以行得通,但我的直觉告诉我应该有一个更“美学”的解决方案。 第二点:这就是我一直在寻找的。这解决了我遇到的问题。 - Mark

1

在这里,我可能会使用模板标签。 我曾经遇到过类似的情况,即在同一页上以不同格式多次呈现日历信息。 我处理的方法是将查询到的数据传递到请求上下文中,然后只需将该查询集用作模板标记的参数即可。 结果是你可以得到像这样的模板语法:

视图

def my_view(request, *args, **kwargs):
    yearly_sales_qs = SaleRecord.objects.filter(param=value)
    monthly_sales_qs = SalesRecord.objects.filter(param=foo)

    return render_to_response( ..., locals(), ... )

模板

{% load data_tags %}

<div class="year">
    {% render_data_table for yearly_sales_qs %}
    {% render_bar_chart for yearly_sales_qs %}
</div>

<div class="month">
    {% render_data_table for monthly_sales_qs %}
    {% render_bar_chart for monthly_sales_qs %}
</div>

那么如何制作这样的东西呢?首先查看 Django 文档中关于 自定义模板标签和过滤器 的内容。这比 Django 其余部分更难入手,但一旦掌握了它,就会变得非常容易。

  • 在您的应用程序文件夹中创建一个名为“templatetags”的文件夹。
  • 在该新文件夹中创建一个空白文件“__init__.py
  • 将 templatetags 文件夹的位置添加到 settings.py 中的 TEMPLATE_DIRS 设置中(如果尚未存在)。

因为我们将制作多个这样的内容,所以我们可以制作一个基础模板标签,我们将从中继承封装我们基本功能...

data_tags.py(存储在 templatetags 文件夹中)

class DataForTag(tempalte.Node):
    @classmethod
    def handle_token(cls, parser, token, template):
        tokens = token.contents.split()
        if tokens[1] != 'for':
                raise template.TemplateSyntaxError("First argument in %r must be 'for'" % tokens[0])

        if len(tokens) == 3:
            return cls(queryset=parser.compile_filter(tokens[2]), template=template)
        else:
            raise template.TemplateSyntaxError("%r tag requires 2 arguments" % tokens[0])

    def __init__(self, queryset=None, template=None):
        self.queryset = queryset
        self.template = template

    def render(self, context):
        return render_to_string(self.template, {'queryset':self.queryset})

然后我们可以创建个体标签,用来处理我们需要的任何内容...

@register.tag
def render_bar_chart(parser, token):
    return DataForTag.handle_token(parser, token, 'data/charts/barchart.html')

@register.tag
def render_pie_chart(parser, token):
    return DataForTag.handle_token(parser, token, 'data/charts/piechart.html')    

@register.tag
def render_data_table(parser, token):
    return DataForTag.handle_token(parser, token, 'data/table.html')   

谢谢T.Stone。这可能解决了我的问题。我需要先测试一下来确保它的可行性。不管怎样,你的回答让我学到了很多关于标签的知识,这将会在将来很有用。 - Mark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接