xlwings + Django:如何不松动连接

时间:2017-08-02 21:13:19

标签: django xlwings

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

  1. 用户以网络形式输入数据
  2. 将表单数据发送到Django后端视图函数" run_model(request)"
  3. 解析请求对象以获取用户输入,然后使用xlwings在excel模型的输入表中填充命名范围以与电子表格模型交互(使用sheet.range函数)
  4. 运行"计算()"在电子表格上
  5. 使用xlwings和命名范围从电子表格中的另一个标签读取输出(同样,使用sheet.range函数)。
  6. 问题是与Excel进程的连接不断被Django杀死(我相信它将每个请求作为一个单独的进程处理),所以我最多可以获得一个请求(通过导入xlwings in < / em>视图功能)但是当我发送第二个请求时,连接已经死亡,并且它不会重新激活。

    基本上,如何在请求之间保持与工作簿的连接,或者至少为每个请求重新打开连接?

1 个答案:

答案 0 :(得分:1)

好的,最后实现了一个简单的“电子表格服务器”来解决Django杀死连接的问题。

首先为服务器(server.py)编写代码,然后从命令行args(start_server.py)启动它,然后让我的视图在需要使用它时打开与该模型的连接(在views.py)。

所以,我不得不将我的(Excel + xlwings)和Django分离成独立的进程来保持接口清洁并控制Django对我的speadsheet模型的访问量。现在工作正常。

start_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})