如何从JavaScript调用Python脚本?

3

我有一个后端Python脚本,它从SQLAlchemy引擎中检索数据。我想在搜索框中显示这些数据,用户可以滚动列表并选择数据。我看到有一些类似的问题和回答(使用ajax调用Python脚本),但我仍然不太清楚。以下是我的Python脚本:

# models.py

from sqlalchemy import create_engine
from sqlalchemy.engine.url import URL
from sqlalchemy.ext.declarative import declarative_base
import pandas as pd

aURL = URL(drivername='mysql', username='chlee021690',  database = 'recommender')
engine = create_engine(aURL, echo=True)

sql_command = 'SELECT product_id FROM bestbuy_data'

results = pd.read_sql(sql = sql_command, con = engine)

有人能告诉我如何创建JavaScript代码来检索结果并在我的表单中呈现吗?谢谢。

2个回答

8
步骤1:将您的脚本作为Web服务提供。您可以使用CGI,也可以使用一些很酷的服务器框架,如CherryPy、web.py或Flask,它们可以独立运行或WSGI方式运行。
步骤2:向步骤1提供的URL发出AJAX调用,可以手动进行(查找XmlHttpRequest示例),也可以使用jQuery或其他框架轻松实现(jQuery.ajax()jQuery.get())。
这是两个单独的任务,都有很好的文档记录在网上。如果您有更具体的问题,请再次提问,并说明您卡在哪里。
还有许多完整包的示例可用("python ajax example"),例如this

URL必须是Web地址吗?我不能使用代码路径吗?顺便说一下,我正在使用Flask。 - user2585578
是的,它必须是一个网址。如果您使用代码的路径,您将得到代码本身,而不是执行结果。 - Amadan

0

你的Python服务器需要完成两件事:

  1. 提供AJAX JavaScript文件本身(通过GET)
  2. 响应来自Web客户端的调用(通过POST)。

此外,它应该是线程化的,以支持多个同时连接。 以下是一个示例,展示如何使用内置的BaseHTTPServer完成上述所有操作。

JS(放在static/hello.html中通过Python提供服务):

<html><head><meta charset="utf-8"/></head><body>
Hello.

<script>

var xhr = new XMLHttpRequest();
xhr.open("POST", "/postman", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
    value: 'value'
}));
xhr.onload = function() {
  console.log("HELLO")
  console.log(this.responseText);
  var data = JSON.parse(this.responseText);
  console.log(data);
}

</script></body></html>

Python服务器(用于测试):

import time, threading, socket, SocketServer, BaseHTTPServer
import os, traceback, sys, json


log_lock           = threading.Lock()
log_next_thread_id = 0

# Local log functiondef


def Log(module, msg):
    with log_lock:
        thread = threading.current_thread().__name__
        msg    = "%s %s: %s" % (module, thread, msg)
        sys.stderr.write(msg + '\n')

def Log_Traceback():
    t   = traceback.format_exc().strip('\n').split('\n')
    if ', in ' in t[-3]:
        t[-3] = t[-3].replace(', in','\n***\n***  In') + '(...):'
        t[-2] += '\n***'
    err = '\n***  '.join(t[-3:]).replace('"','').replace(' File ', '')
    err = err.replace(', line',':')
    Log("Traceback", '\n'.join(t[:-3]) + '\n\n\n***\n*** ' + err + '\n***\n\n')

    os._exit(4)

def Set_Thread_Label(s):
    global log_next_thread_id
    with log_lock:
        threading.current_thread().__name__ = "%d%s" \
            % (log_next_thread_id, s)
        log_next_thread_id += 1


class Handler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(self):
        Set_Thread_Label(self.path + "[get]")
        try:
            Log("HTTP", "PATH='%s'" % self.path)
            with open('static' + self.path) as f:
                data = f.read()
            Log("Static", "DATA='%s'" % data)
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(data)
        except:
            Log_Traceback()

    def do_POST(self):
        Set_Thread_Label(self.path + "[post]")
        try:
            length = int(self.headers.getheader('content-length'))
            req   = self.rfile.read(length)
            Log("HTTP", "PATH='%s'" % self.path)
            Log("URL", "request data = %s" % req)
            req = json.loads(req)
            response = {'req': req}
            response = json.dumps(response)
            Log("URL", "response data = %s" % response)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("content-length", str(len(response)))
            self.end_headers()
            self.wfile.write(response)
        except:
            Log_Traceback()


# Create ONE socket.
addr = ('', 8000)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(5)

# Launch 10 listener threads.
class Thread(threading.Thread):
    def __init__(self, i):
        threading.Thread.__init__(self)
        self.i = i
        self.daemon = True
        self.start()
    def run(self):
        httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)

        # Prevent the HTTP server from re-binding every handler.
        # https://dev59.com/nlYO5IYBdhLWcg3wL-vY
        httpd.socket = sock
        httpd.server_bind = self.server_close = lambda self: None

        httpd.serve_forever()
[Thread(i) for i in range(10)]
time.sleep(9e9)

控制台日志(Chrome):

HELLO
hello.html:14 {"req": {"value": "value"}}
hello.html:16 
{req: {}}
req
:
{value: "value"}
__proto__
:
Object

控制台日志(火狐浏览器):

GET 
http://XXXXX:8000/hello.html [HTTP/1.0 200 OK 0ms]
POST 
XHR 
http://XXXXX:8000/postman [HTTP/1.0 200 OK 0ms]
HELLO hello.html:13:3
{"req": {"value": "value"}} hello.html:14:3
Object { req: Object }

控制台日志(Edge):

HTML1300: Navigation occurred.
hello.html
HTML1527: DOCTYPE expected. Consider adding a valid HTML5 doctype: "<!DOCTYPE html>".
hello.html (1,1)
Current window: XXXXX/hello.html
HELLO
hello.html (13,3)
{"req": {"value": "value"}}
hello.html (14,3)
[object Object]
hello.html (16,3)
   {
      [functions]: ,
      __proto__: { },
      req: {
         [functions]: ,
         __proto__: { },
         value: "value"
      }
   }

Python 日志:

HTTP 8/postman[post]: PATH='/postman'
URL 8/postman[post]: request data = {"value":"value"}
URL 8/postman[post]: response data = {"req": {"value": "value"}}

此外,您可以通过在将套接字传递给BaseHTTPServer之前对其进行包装来轻松添加SSL。


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