【问题标题】:Passing JSON data from server to client with Flask使用 Flask 将 JSON 数据从服务器传递到客户端
【发布时间】:2017-05-13 06:39:59
【问题描述】:

我对 Flask 完全陌生,正在尝试弄清楚如何使用 d3js 强制布局显示 networkx 图形数据。以下是相关的 Python 代码:

@app.route("/")
def index():
    """
    When you request the root path, you'll get the index.html template.

    """
    return flask.render_template("index.html")


@app.route("/thread")
def get_graph_data(thread_id: int=3532967):
    """
    returns json of a network graph for the specified thread
    :param thread_id:
    :return:
    """
    pqdict, userdict = graphs.get_post_quote_dict(thread_id)
    G = graphs.create_graph(pqdict)
    s = graphs.graph_to_node_link(G, remove_singlets=True) # returns dict
    return flask.jsonify(s)

这里是 index.html 文件:

<!DOCTYPE html>
<html>
<head>
    <title>Index thing</title>
    <script type="text/javascript" src="http://d3js.org/d3.v2.js"></script>
    <link type="text/css" rel="stylesheet" href="templates/graph.css"/>
</head>
<body>
<div id="chart"></div>
<script>
    var w = 1500,
        h = 1500,
        fill = d3.scale.category20();

    var vis = d3.select("#chart")
        .append("svg:svg")
        .attr("width", w)
        .attr("height", h);

    d3.json("/thread", function (json) {
        var force = d3.layout.force()
            .charge(-120)
            .linkDistance(30)
            .nodes(json.nodes)
            .links(json.links)
            .size([w, h])
            .start();

        var link = vis.selectAll("line.link")
            .data(json.links)
            .enter().append("svg:line")
            .attr("class", "link")
            .style("stroke-width", function (d) {
                return Math.sqrt(d.value);
            })
            .attr("x1", function (d) {
                return d.source.x;
            })
            .attr("y1", function (d) {
                return d.source.y;
            })
            .attr("x2", function (d) {
                return d.target.x;
            })
            .attr("y2", function (d) {
                return d.target.y;
            });

        var node = vis.selectAll("circle.node")
            .data(json.nodes)
            .enter().append("svg:circle")
            .attr("class", "node")
            .attr("cx", function (d) {
                return d.x;
            })
            .attr("cy", function (d) {
                return d.y;
            })
            .attr("r", 5)
            .style("fill", function (d) {
                return fill(d.group);
            })
            .call(force.drag);

        vis.style("opacity", 1e-6)
            .transition()
            .duration(1000)
            .style("opacity", 1);

        force.on("tick", function () {
            link.attr("x1", function (d) {
                return d.source.x;
            })
                .attr("y1", function (d) {
                    return d.source.y;
                })
                .attr("x2", function (d) {
                    return d.target.x;
                })
                .attr("y2", function (d) {
                    return d.target.y;
                });

            node.attr("cx", function (d) {
                return d.x;
            })
                .attr("cy", function (d) {
                    return d.y;
                });
        });
    });
</script>
</body>
</html>

很明显,d3.json() 函数需要一个静态 JSON 文件的位置,在这种情况下,我试图根据请求 URL 动态生成该文件。

我已经尝试了大约十几种我在这里找到的方法。根据以下建议,我尝试了:

@app.route("/")
def index():
    """
    When you request the root path, you'll get the index.html template.

    """
    return flask.render_template("index.html")


@app.route("/thread")
def get_graph_data():

    """
    returns json of a network graph for the specified thread
    :param thread_id:
    :return:
    """
    thread_id = request.args.get("thread_id", 3532967, type=int)
    pqdict, userdict = graphs.get_post_quote_dict(thread_id)
    G = graphs.create_graph(pqdict)
    s = graphs.graph_to_node_link(G, remove_singlets=True)
    return jsonify(s)

模板 index.html 未更改,并导航到“http://localhost/thread?thread_id=12345”,但这失败了,因为它在页面上打印 ID 12345 的 JSON,而不是呈现 javascript。

所以总结一下,我目前的目标是从URL(“.../showgraph?threadid=whatever...”)在Python方法中指定一个参数,在Python代码中生成一个json,并通过它回到 html/js。我该如何做到这一点?

【问题讨论】:

    标签: python json d3.js flask


    【解决方案1】:

    你真的很亲密!

    首先,声明:“显然 d3.json() 函数想要一个静态 JSON 文件的位置”是不正确的。

    d3.json()d3-request 库的一部分,因此是一种 XHR 方法(例如,需要一个 URL,它可以是像 data.json 这样的静态 JSON,但不是文字 JSON 数据)。

    我会调整您的 Flask 路由以接受 GET 参数,因为该函数只会通过 URL 接受参数:

    @app.route("/thread")
    def get_graph_data():
        thread_id = request.args.get("thread_id", 3532967, type=int)
        pqdict, userdict = graphs.get_post_quote_dict(thread_id)
        G = graphs.create_graph(pqdict)
        s = graphs.graph_to_node_link(G, remove_singlets=True) # returns dict
        return flask.jsonify(s)
    

    我的意思是,如果你想使用函数参数,你需要做这样的事情:

    @app.route("/thread/<int:thread_id>")
    def get_graph_data(thread_id):
        ...
    

    然后,稍微调整一下您的 XHR 调用以发送 GET 参数:

    var url = "/thread?thread_id=" + id.toString();
    d3.json(url, function (json) {
        var force = d3.layout.force()
            .charge(-120)
            .linkDistance(30)
            .nodes(json.nodes)
            .links(json.links)
            .size([w, h])
            .start();
    
       // a bunch more js that i copied and pasted from a tutorial
    });
    

    应该没问题的。

    另外,仅供参考,如果您想使用 Jinja2 将对象“读取”到 Javascript 对象中,您需要使用 2 个过滤器:{{ data|tojson|safe }}

    【讨论】:

    • 所以从你所说的来看,我收集到 d3.json() 接受一个 URL(即静态文件或来自 REST API 的东西),但要做到这一点,我需要以某种方式调用一个单独的方法来实际渲染模板,不是吗?我尝试了您的第一个 sn-p 建议的(稍作修改--request.args.get 而不是 requests.get)版本,但它只是在页面上打印原始 JSON 而不是渲染 JS。这是我反复遇到的另一个问题...
    • 是的,它是一种异步方法,因此接受任何有效的 http URL。 requests.get 是一个错误,很好。你能更详细地解释发生了什么吗?也许分享更多代码。
    • 我粘贴了几乎所有的完整代码(省略了导入和“if name == 'main'”位),然后我认为我的方法可能做错了什么......当我转到 url [domain]/thread?thread_id=12345 它会做所有正确的后端工作,但它只是在字面上打印 { "source": 1, "target": 2 } etc on页面而不是呈现该 JSON。也许我不应该直接访问 URL?
    • 是的,我假设您正在加载一个 html 页面,然后使用 d3.json 调用此路由,因此它将异步加载
    • 我想我不是很清楚而且很混乱......如果我想使用你的第一个 Python sn-p,这需要我使用你最后一个 javascript sn-p--否则 "/线程”总是会返回默认路径。这要求我将“12345”传递给某个东西,以便“id.toString()”返回 12345,因此 d3.json 参数变为“/thread?thread_id=12345”,对吗?我不明白“id.toString()”指的是什么或如何将 12345 传递给 d3.json
    【解决方案2】:

    解决办法是:

    Python:

    @app.route("/thread")
    def get_graph_data():
    
        """
        returns json of a network graph for the specified thread
        :param thread_id:
        :return:
        """
        thread_id = request.args.get("thread_id", 3532967, type=int)
        pqdict, userdict = graphs.get_post_quote_dict(thread_id)
        G = graphs.create_graph(pqdict)
        s = graphs.graph_to_node_link(G, remove_singlets=True)
        return json.dumps(s)
    
    
    @app.route("/showgraph")
    def showgraph():
        thread_id = request.args.get("thread_id", 3532967, type=int)
        return render_template("index.html", threadid=thread_id)
    

    HTML/Jinja2:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Index thing</title>
        <script type="text/javascript" src="http://d3js.org/d3.v2.js"></script>
        <link type="text/css" rel="stylesheet" href="templates/graph.css"/>
    </head>
    <body>
    <div id="chart"></div>
    <script>
        var w = 1500,
            h = 1500,
            fill = d3.scale.category20();
    
        var vis = d3.select("#chart")
            .append("svg:svg")
            .attr("width", w)
            .attr("height", h);
    
        d3.json("/thread?thread_id={{ threadid }}", function (json) {
            var force = d3.layout.force()
                .charge(-120)
                .linkDistance(30)
                .nodes(json.nodes)
                .links(json.links)
                .size([w, h])
                .start();
    
            // irrelevant stuff
        });
    </script>
    </body>
    </html>
    

    需要单独的方法来返回 JSON 并呈现页面。必须两次解析 thread_id arg 似乎仍然很愚蠢,但无论如何。接受了 PJ 的回答,因为这是问题的 99%!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-16
      • 2014-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多