使用Flask将JSON数据从服务器传递到客户端
我完全是Flask的新手,正试图弄清楚如何使用d3js强制布局显示networkx图形数据。下面是相关Python代码:使用Flask将JSON数据从服务器传递到客户端
@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”,但这种失败,因为它是在页面上打印的JSON用于ID为12345,而不是渲染的JavaScript。总结起来,我目前的目标是通过URL(“.../showgraph?threadid = whatever ...”)在Python方法中指定一个参数,并在Python代码中生成一个json,并且把它传回给html/js。我该如何做到这一点?
你真的很接近!
首先,声明:“显然d3.json()函数需要一个静态JSON文件的位置”是不正确的。
d3.json()是d3-request
库的一部分,并且同样地,是一种方法,XHR(例如期望的URL,这可能是一个静态JSON像data.json
,但不是字面JSON数据)。
我会调整自己的瓶路线接受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)
我的意思在这里,如果你想使用的功能参数你”是d需要做这样的事情:
@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 }}
的解决方案是:
的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%的问题!
所以从你的意思,我收集d3.json()接受一个URL(即静态文件或从REST API的东西),但要做到这一点,我需要调用一个单独的方法莫名其妙地呈现模板,不是吗?我尝试了第一个片段建议(稍微修改--request.args.get而不是'requests.get')版本,但它只是在页面上打印原始JSON而不是渲染JS。这是我反复遇到的另一个问题... – stuart
是的,它是一种异步方法,因此接受任何有效的http URL。 requests.get是个错误,很好。你能更详细地解释发生了什么吗?也许分享更多的代码。 – abigperson
我粘贴了几乎所有的代码(省略导入和“if __name__ =='__main__'”位),我想我可能会在我的方法中做错事情...当我去到网址'[[域] /线程?thread_id = 12345'它做所有正确的后端的东西,但它只是在页面上打印{“source”:1,“target”:2}等,而不是呈现该JSON。也许我不应该直接去URL? – stuart