Flask:如何使用post方法作为后台任务运行函数,然后在另一个类中访问它

时间:2018-04-06 08:44:00

标签: python post flask

我正在使泵自动化,只有当土壤湿度值(从土壤湿度传感器获得)超过某个值时才打开。就是这样:

  1. 用户从下拉列表中选择一个值(土壤湿度的阈值)

  2. python脚本不断检查传感器的值是否大于下拉列表中选择的值(这就是为什么我需要让它作为后台任务运行)

  3. 用户可以使用网页上的OFF按钮终止后台任务来关闭自动化过程。

  4. 我尝试了以下操作,但我收到working outside of request context错误:

    web_plants.py (调用python soil_on.py脚本):

    @app.route("/threshold", methods=['POST', 'GET'])
    def threshold():
        tvalue= -1 #get value from dropdown
        msg = ''
        if request.method == "POST":
               msg= "rating above 3"
               os.system("python soil_on.py&")
        templateData = template(text = msg) #display text using template()
        return render_template('index.html', **templateData)
    

    soil_on.py (从auto_Irrigation()类调用water函数:

    import water
    
    if __name__ == "__main__":
        water.auto_Irrigation()
    

    water.py (有auto_Irrigation()

    app = Flask(__name__)
    
    def template(title = "HELLO!", text = ""):
    templateDate = {
        'text' : text,
        'tvalues' : getTValues(),
        'selected_tvalue' : -1
    }
    return templateDate
    
    def getTValues():
      return (10, 11, 15, 2, 1)
    
    @app.route("/", methods=['POST', 'GET'])
    def auto_Irrigation():
        tvalue= -1 #get value from dropdown
       # msg = ''
        if request.method == "POST":
            tvalue = int(request.form['tvalue'])
            if tvalue> 3:
                GPIO.output(40, GPIO.HIGH)
            else:
               GPIO.output(40, GPIO.LOW)
        return render_template('index.html', **templateData)
    

    的index.html

    <h2> {{text}} </h2>
    <form action= "{{ url_for('threshold') }}" method="POST">
    
         <select name= 'tvalue'>
          {% for tvalue in tvalues %}
            {% if selected_tvalue == tvalue %}
                <option value="{{ tvalue }}" selected='selected'>{{ tvalue }}</option>
            {% else %}
                 <option value="{{ tvalue }}" >{{ tvalue }}</option>
            {% endif %}
          {% endfor %}
    
          </select>
    
         <input type="submit" value="Submit" />
    </form>
    

    我不确定如何将该功能作为后台任务。目前这对我有用,但该功能没有作为后台任务运行(所以它只检查值并打开/关闭泵):

    的index.html

    <h2> {{text}} </h2>
    <form action= "{{ url_for('threshold') }}" method="POST">
    
         <select name= 'tvalue'>
          {% for tvalue in tvalues %}
            {% if selected_tvalue == tvalue %}
                <option value="{{ tvalue }}" selected='selected'>{{ tvalue }}</option>
            {% else %}
                 <option value="{{ tvalue }}" >{{ tvalue }}</option>
            {% endif %}
          {% endfor %}
    
          </select>
    
         <input type="submit" value="Submit" />
    </form>
    

    web_plants.py:(为了使这篇文章更容易理解,简化了函数threshold()

    def template(title = "HELLO!", text = ""):
        templateDate = {
            'text' : text,
            'tvalues' : getTValues(),
            'selected_tvalue' : -1
        }
        return templateDate
    
    def getTValues():
        return (10, 11, 15, 2, 1) 
    
    @app.route("/threshold", methods=['POST', 'GET'])
    def threshold():
        tvalue= -1 #default value
        msg = ''
        if request.method == "POST":            
            tvalue = int(request.form['tvalue'])
            if tvalue> 3:
                msg= "rating above 3"
    
        #generating template data
        templateData = template(text = msg)
        templateData['selected_tvalue'] = tvalue 
    
        return render_template('index.html', **templateData)
    

1 个答案:

答案 0 :(得分:1)

考虑使用Celery,它是一个异步任务队列。您可以继续运行长时间运行的作业,获取状态更新(甚至是自定义更新)。

这些链接可以帮助您了解它的工作原理:

https://github.com/miguelgrinberg/flask-celery-example

https://blog.miguelgrinberg.com/post/using-celery-with-flask

您甚至可以查看Celery文档。

这是您如何实现功能的示例。你可以从那里继续前进。

/tasks.py

@celery.task
def my_task(self, threshold):
    if sensor_val < threshold:
        self.update_state(state="Sensor Value below threshold", meta={'sensor_val':sensor_val, 'threshold':threshold})
    else:
        self.update_state(state="Sensor Value past threshold. Please check.", meta={'sensor_val':sensor_val, 'threshold':threshold})
        """Do whatever you would like to do"""

/views.py

def sensor_check(request):
    if request.method == "POST":
        threshold = request.POST['threshold']
        from tasks import my_task
        job = my_task.delay(threshold)
        return HttpResponseRedirect(reverse("task_status")+"?job_id="+job.id)

def task_status(request):
    if 'job_id' in request.GET:
        job_id = request.GET['job_id']
        job = AsyncResult(job_id)
        data = job._get_task_meta()
        return JsonResponse(data)
    else:
        JsonResponse("No job ID given")