3

我正在使用 d3 和 Flask 在浏览器中显示树形图。整个东西在本地存储和操作。

当用户将鼠标悬停在树形图中的每个节点上时,我想显示相关图像。

对于树形图所基于的 JSON 数据,我使用 url_for 和我的静态文件夹,如下所示:

d3.json("{{ url_for('static', filename=json_data) }}", function(error, flare) {
    // Lots of code

包含 d3 也是一样的:

<script src="{{ url_for('static', filename='d3.js') }}"></script>

但是,当涉及到我想在悬停时出现的图像时,我使用来自 JSON 的数据来创建图像的名称。因为这意味着使用 JavaScript 变量而不是 python 变量,所以我看不到如何使用 url_for 显示它。

作为替代方案,我尝试使用一系列不同的绝对和相对路径,但没有任何效果。我读过一些关于 Firefox 不想显示本地文件的内容,但这肯定不适用于在我的计算机上运行的东西吗?我可以在浏览器中正常显示大量本地文件。无论哪种方式,我都安装了一个名为 LocalLink 的附加组件。这是我尝试使用此方法的代码:

var img_path;
d3.selectAll( ".node" ).on( "mouseover", function(d) {
  img_path = "{{ image_path }}" + d.name + ".png";
  document.getElementById('thumb').src=img_path;
  document.getElementById('thumb').style.display='block';

在这里,python image_path 变量类似于 r"file:///C:/Python27/my/app/folders/etc/"

这几乎可以工作。图像不会出现在悬停时,但如果我使用 Firebug 并将鼠标悬停在 HTML 中的适当标签上,正确的图像会在我的光标旁边显示为缩略图。

我尝试使用引用“file:///.....”位置的图像创建一个简单的 HTML 页面。这样可行。这让我觉得这个方法的问题是 Flask。网站位置的绝对路径似乎没有问题(我已经测试过了,它有效),所以我猜测 Flask 不喜欢本地文件位置的绝对路径。

因此,有几种可能性可以解决这个问题:

  • 有一种方法可以将 url_for 与 JavaScript 中生成的变量一起使用。
  • 有一种方法可以将信息传递回 python 变量并在 url_for 中使用它。
  • 有一种方法可以让 Flask 使用“file:///.....”格式显示这些图像。

还有其他方法吗?

我考虑过的唯一其他选择是将整个事情转移到网上。但是,我对 Python 托管不是很熟悉,而且这个应用程序使用了 Twisted 和 PyQT。我不知道如何将它们安装在服务器上。我什至不知道我构建的内容是否可以在线使用 - 你可以在实时网站上使用 Twisted 或 PyQT 吗?我对 Twisted 的所作所为只有模糊的感觉。

如果人们认为这是我最好/唯一的选择,我将详细解释我的应用程序是如何工作的,但在那之前我不会把事情搞得一团糟。

4

1 回答 1

13

我假设您正在本地运行 Flask 应用程序(在您的浏览器中,您正在输入类似的内容localhost:8000)。

首先,您需要了解是做什么url_for的。它可以帮助您生成 HTML 需要加载的静态文件(在您的情况下为图像或 javascript 源文件)的 URL。所以,当你有...

<script src="{{ url_for('static', filename='d3.js') }}"></script>

...模板引擎实际上将其转换为...

<script src="/static/d3.js"></script>

如果您愿意,您可以在模板中输入以上内容(但如果您需要将路径更改为 /media 而不是 /static,则使用 url_for 会很有帮助:现在您只需在一个地方进行更改即可而不是更改所有链接)。

因此,这意味着当您运行 Flask 并使用上述 HTML 加载页面时,浏览器知道在“localhost:8000/static/d3.js”中找到 d3.js 脚本。浏览器向服务器(你的烧瓶应用程序)发送一个请求,Flask 识别它正在寻找一个静态文件(因为路径以 开头)并返回存储在你项目目录中/static的 d3.js 文件。static

现在,假设您的/static目录中有一个名为static/images/img1.png. 要显示它,您需要生成与该图像相关的 URL(即/static/images/img1.png)。在 Flask 中,您通常会键入:

<img src="{{ url_for('static', filename='img/img01.png') }}"></img>

...这将转化为...

<img src="/static/img/img01.png"></img>

如果你愿意,你可以输入这个 URL。因此,您的 javascript 可以只生成这个 URL 并且它会工作。

现在,也许您已经知道这一点,但困扰您的是为什么您不能执行类似file:///C:/Python27/my/app/folders/etc/. 首先,您说 Flask 没有按您的预期处理此请求。好吧,那是因为 Flask 根本没有处理这个请求!请记住,Flask 运行在类似localhost:8000. 如果您键入<img src="file:///C:/Python27/my/app/folders/etc"></img>,则浏览器不会向 发送检索此文件的请求localhost:8000,而是尝试使用浏览器在本地检索文件。同样,如果您的页面上有一个链接google.com,您的浏览器不会将点击该链接的用户发送到您的烧瓶应用程序,他们会将其发送给 Google!

出于安全原因,如果您连接到的网站不是本地站点(例如,example.com/index.html而不是file:///home/mark/index.html),Firefox 将不允许您直接从磁盘访问文件。这是有道理的,因为否则访问 example.com,网站可以将您硬盘上的任何文件加载到 javascript 可以访问的网页中,然后将该文件的信息发送回网站!

碰巧它localhost:8000被认为是浏览器的非本地站点。因此,Firefox 将不允许您file:///...从该页面访问这些资源。

所以,这不是 Flask 的问题:这是使用浏览器做浏览器不想做的事情的问题。

现在,您的解决方案究竟是什么将取决于您的应用程序的需求。最直接的解决方案是使您要显示的图像位于/static项目目录中。

但是,如果您想创建一个 Flask 项目来处理放置在硬盘驱动器上任何位置的文件(没有先从“上传”页面从中选择文件),您可能选择了错误的工具(一个 web-基于应用程序)的工作。

于 2013-09-25T14:52:22.120 回答