如何从异步龙卷风发布请求中发送响应以在html模板上呈现?

时间:2016-03-14 23:43:18

标签: jquery python-2.7 asynchronous response tornado

我试图掌握使用龙卷风的异步功能。到目前为止,我只取得了一定的成功。我使用我发现的here的修改版本来协助我的异步..也许这不是最好的方式,你告诉我你的想法或者是否有更好的方法。这是我用来帮助处理异步请求的subprocess_helper.py文件。

import tornado.process
import subprocess
import logging

from tornado.gen import Task, Return, coroutine
from tornado.ioloop import IOLoop

STREAM = tornado.process.Subprocess.STREAM
@coroutine
def call_subprocess(cmd, stdin_data=None, stdin_async=False):
  """
  Wrapper around subprocess call using Tornado's Subprocess class.
  """
  stdin = STREAM if stdin_async else subprocess.PIPE

  sub_process = tornado.process.Subprocess(
      cmd, stdin=stdin, stdout=STREAM, stderr=STREAM
  )

  if stdin_data:
      if stdin_async:
          yield Task(sub_process.stdin.write, stdin_data)
      else:
          sub_process.stdin.write(stdin_data)

  if stdin_async or stdin_data:
      sub_process.stdin.close()

  result, error = yield [
      Task(sub_process.stdout.read_until_close),
      Task(sub_process.stderr.read_until_close)
  ]

  raise Return((result, error))


def on_timeout():
  logging.info("timeout")
  #IOLoop.instance().stop()
  #IOLoop.instance().stop()

这是视图..

import app.basic
import tornado.web
import time
import os
import shlex

from tornado.ioloop import IOLoop
from tornado.gen import coroutine

#from datetime import datetime
from lib import subprocess_helper
from lib import ad_sizesdb, sitesdb, audit_notesdb


class Repull(app.basic.BaseHandler):
  @tornado.web.authenticated
  def get(self):
   if self.get_secure_cookie("account_type") not in ['admin']:
     self.redirect('/')
   else:
     slug = self.get_argument('slug','')
     size = self.get_argument('ad_size', '')

     ad_sizes = ad_sizesdb.get_ad_sizes()
     slugs = sitesdb.get_all_slugs()
     self.render('admin_tools/repull.html', active_section='repull_invocation', ad_sizes=ad_sizes, slug=slug, slugs=slugs, size=size, expand_tools=True)

  @tornado.web.authenticated
  @coroutine
  def post(self):
    slug = self.get_argument('slug','')
    size = self.get_argument('ad_size', '')
    if slug != '' and size != '':
      seconds_to_wait = 300
      deadline = time.time() + seconds_to_wait
      IOLoop.instance().add_timeout(deadline, subprocess_helper.on_timeout)

      file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)).replace('app', 'scripts/pull_invocation_codes.py'))
      #cmd = shlex.split('python {0} "{1}" "adtech" "{2}"'.format(file_path, slug, size))
      cmd = 'ls'
      result, error = yield subprocess_helper.call_subprocess(cmd, stdin_async=True)

      if result != '':
        msg = 'invocation code for {0}_{1} pulled'.format(slug, size)
        #log_audit_note(msg)
        self.api_response(msg)
      else:
        msg = 'invocation for {0}_{1} not pull something happened'.format(slug, size)
        #log_audit_note(msg)
        self.api_response(msg)
    else:
      self.error(400, 'slug or ad size blank')
    #self.redirect('/admin/admin_tools/repull??ad_size={0}&slug={1}'.format(size, slug))

模板

{% set active_section = 'admin_tools' %}
{% extends ../admin.html %}

{% block middle_content %}
  <div class="col-sm-6">
    <form name="form" action="/admin/admin_tools/repull" method="post">
      <div class="form-group">
        <label>Ad Size</label>
        <select id="ad_size" name="ad_size" data-init-plugin="select2" style="width:100%;">
          <option value=""></option>
          {% for size in ad_sizes %}
            <option value='{{size['size']}}' {% if size['size'] == size %} selected {% end %}>{{size['size']}}</option>
          {% end %}
        </select>
      </div>
      <div class="form-group">
        <label>Slugs</label>
        <select id="slug" name="slug" data-init-plugin="select2" style="width:100%;">
          <option value=""></option>
          {% for s in slugs %}
            <option value='{{s['slug']}}' {% if s['slug'] == slug %} selected {% end %}>{{s['slug']}}</option>
          {% end %}
        </select>
      </div>
      <button type="submit" id="submit" class="btn btn-primary">Pull Adtech Invocation Code</button>
    </form>
  </div>
  <div class="col-sm-6">
    <div>Notes:</div>
    <div id="notes"></div>
  </div>
{% end %}

{% block javascript %}
  <script>
  $(document).ready(function() {
    $("form").submit(function(){
      $('#notes').html('Running for invocation for ' + slug + '_' + adsize);
      $.post($(this).attr("action"), $(this).serialize(), function(data) { 
        $('#notes').html(data['data']); 
        return false; 
      });
      return false;
    });
  });
  </script>
{% end %}

所以有点背景。我之所以需要这个调用是异步的,是因为post请求触发了另一个使用selenium来帮助自动化的文件。我不太了解并希望得到帮助的一些内容包括使用IOLoop.instance().stop()上面的链接使用它来帮助解决超时问题,以及之后的问题如何结束。我评论了它,因为如果我没有龙卷风线程在帖子的末尾终止。考虑到我正在调用的方法的名称,我认为这是有道理的...总的来说,我希望能够在完成后运行异步并获得某种响应,以便我可以触发一些模板上的视觉之王让用户有某种线索发生/完成/失败。我做错了什么?我该如何解决?如果这不是最好的方法是什么?先谢谢。
更新:我添加了模板,在考虑之后,我想我想要的是在模板上正确呈现的响应。我添加了一张我正确得到的图像,这不是我的意思。该消息在空白页面上呈现,但是如果你看一下html模板,当我收到响应数据时,我想将jquery注入到div中。我在jQuery enter image description here

中返回false

1 个答案:

答案 0 :(得分:0)

由于我发了多个帖子,我不得不阻止默认

$("form").submit(function(e){
      e.preventDefault();
      var slug = $('#slug').val();
      var adsize = $('#ad_size').val();
      if((slug && adsize) != ''){
        $('#notes').html('Running for invocation for ' + slug + '_' + adsize + ' if you don\'t want to wait for the reponse you can check the audit notes later');
        $.post($(this).attr("action"), $(this).serialize(), function(data) { 
          $('#notes').html(data['data']); 
          return false; 
        });
      }
    });