xlwings + Django:如何不丢失连接

xlwings + Django: how to not loose a connection

我正在尝试使用 Django 部署带有网页前端的 spreadsheet 模型。网络 "app" 流程很简单:

  1. 用户在网络表单中输入数据
  2. 将表单数据发送到 Django 后端视图函数"run_model(request)"
  3. 解析请求对象以获取用户输入,然后在 excel 模型的输入中填充命名范围 sheet 使用 xlwings 与传播 sheet 模型交互(sheet.range使用函数)
  4. 运行 "calculate()" 上差sheet
  5. 使用 xlwings 和命名范围(再次使用 sheet.range 函数)从传播中的另一个选项卡读取输出sheet。

问题是与 Excel 进程的连接不断被 Django 终止(我相信它将每个请求作为一个单独的进程处理),所以我最多只能处理一个请求(通过导入xlwings 视图函数中)但是当我发送第二个请求时,连接已断开并且不会重新激活。

基本上,我怎样才能在请求之间保持与工作簿的连接,或者至少为每个请求重新打开一个连接?

好的,最终实施了一个简单的 "spreadsheet server" 来解决 Django 终止连接的问题。

首先为服务器编写代码 (server.py),然后编写一些代码从命令行参数启动它 (start_server.py),然后让我的视图在它需要使用它(在 views.py)。

所以,我不得不将我的 (Excel + xlwings) 和 Django 分成独立的进程,以保持界面整洁并控制 Django 对我的电子表格模型的访问权限。现在工作正常。

开始_server.py

"""
Starts spreadsheet server on specified port

Usage: python start_server.py port_number logging_filepath
    port_number: sets server listening to localhost:<port_number>
    logging_filepath: full path to logging file (all messages directed to this file)
"""

import argparse
import os
import subprocess

_file_path = os.path.dirname(os.path.abspath(__file__))

#command line interface
parser = argparse.ArgumentParser()
parser.add_argument('port_number',
help='sets server listening to localhost:<port_number>')
    parser.add_argument('logging_filepath',help='full path to logging file (all messages directed to this file)')
    args = parser.parse_args()

#set up logging
_logging_path = args.logging_filepath
print("logging output to " + _logging_path)
_log = open(_logging_path,'wb')

#set up and start server
_port = args.port_number
print('starting Excel server...')
subprocess.Popen(['python',_file_path + 
  '\server.py',str(_port)],stdin=_log, stdout=_log, stderr=_log)
print("".join(['server listening on localhost:',str(_port)]))

server.py

"""
Imports package that starts Excel process (using xlwings), gets interface
to the object wrapper for the Excel model, and then serves requests to that model.
"""
import os
import sys
from multiprocessing.connection import Listener

_file_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(_file_path)
import excel_object_wrapper

_MODEL_FILENAME = 'excel_model.xls'
model_interface = excel_object_wrapper.get_model_interface(_file_path+"\"+_MODEL_FILENAME)
model_connection = model_interface['run_location']
close_model = model_interface['close_model']

_port = sys.argv[1]
address = ('localhost', int(_port))     
listener = Listener(address)

_alive = True

print('starting server on ' + str(address))
while _alive:
    print("listening for connections")
    conn = listener.accept()
    print 'connection accepted from', listener.last_accepted

    while True:
        try:
            input = conn.recv()
            print(input)
            if not input or input=='close':
                print('closing connection to ' + str(conn))
                conn.close()
                break        
            if input == 'kill':
                _alive = False
                print('stopping server')                               
                close_model()
                conn.send('model closed')
                conn.close() 
                listener.close()
                break
        except EOFError:
                print('closing connection to ' + str(conn))
                conn.close()
                break 
        conn.send(model_connection(*input))

views.py(来自 Django 内部)

from __future__ import unicode_literals

import os

from multiprocessing.connection import Client

from django.shortcuts import render
from django.http import HttpResponse

def run(request):    
    model_connection = Client(('localhost',6000)) #we started excel server on localhost:6000 before starting Django
    params = request.POST
    param_a = float(params['a'])
    param_b = float(params['b'])        
    model_connection.send((param_a ,param_b )) 
    results = model_connection.recv()
    return render(request,'model_app/show_results.html',context={'results':results})