python-flask结合bootstrap实现网页小工具实例-半小时速通版

发布于:2024-04-24 ⋅ 阅读:(24) ⋅ 点赞:(0)

参考:
Python之flask结合Bootstrap框架快速搭建Web应用_支持bootstrap的python软件-CSDN博客
https://blog.csdn.net/lovedingd/article/details/106696832

Bootstrap 警告框 | 菜鸟教程
https://www.runoob.com/bootstrap/bootstrap-alert-plugin.html

flask框架的Jinja2中怎么动态的传入图片啊? - 清风徐来的回答 - 知乎
https://www.zhihu.com/question/478883018/answer/2052587300

二十:jinja2之加载静态文件 - 向前走。 - 博客园
https://www.cnblogs.com/zhongyehai/p/11784648.html

Flask jinja2.exceptions.TemplateSyntaxError: 语法错误|极客笔记
https://deepinout.com/flask/flask-questions/129_flask_jinja2exceptionstemplatesyntaxerror_expected_token_end_of_print_statement_got_posted.html

环境:
win10 / centos6 , python3


背景&问题

临时接到任务,需要写一个网页,该网页接受一个文字输入,向后台发出post请求,后台(linux系统)接收请求后调用一个可执行文件,获取执行结果(包含文字和图片),进行解析后再更新到当前网页中。因为不涉及数据库,也没有太复杂的操作,所以我决定用flask写。

虽然我之前写过django,但那是五年前的事情了,写网站我一直用的是java。所以我花了1h速通flask的基础操作+调试,终于解决了问题

本文除了有基础知识还有这个问题的解决思路,如果不想看基础知识可以直接跳转到解决思路部分。

基础知识

首先需要安装flask-bootstrap

pip install flask-bootstrap

因为是速通,所以直接上例子。相关知识会写在注释里。

helloworld

文件结构:
在这里插入图片描述
myflask.py

from flask import Flask, render_template, request
from flask_bootstrap import Bootstrap
import subprocess
import os

# template_folder: store *.html
app = Flask(__name__, template_folder=os.getcwd() + "/static/templates")
bootstrap = Bootstrap(app)

@app.route('/index')
def index():
    return render_template('index.html')

@app.route('/')
def index1():
    return "hello"

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8080)
	# 如果报错的话可以考虑换成
	# app.run(debug=True, host="127.0.0.1", port=8080)

注意:查资料的时候有说template_folder设为""就是当前路径,然后把*.html放到/static/templates下就能找到。我试了,找不到。。所以还是选择指明。

index.html

{% extends "bootstrap/base.html" %}

{% block title %}Flask{% endblock %}

{% block navbar %}
<p>带有下拉菜单的标签</p>
  <ul class="nav nav-tabs">
    <li class="active"><a href="#">Home</a></li>
    <li><a href="#">SVN</a></li>
    <li><a href="#">iOS</a></li>
    <li><a href="#">VB.Net</a></li>
    <li class="dropdown">
      <a class="dropdown-toggle" data-toggle="dropdown" href="#">
        Java <span class="caret"></span>
      </a>
      <ul class="dropdown-menu">
        <li><a href="#">Swing</a></li>
        <li><a href="#">jMeter</a></li>
        <li><a href="#">EJB</a></li>
        <li class="divider"></li>
        <li><a href="#">分离的链接</a></li>
      </ul>
    </li>
    <li><a href="#">PHP</a></li>
  </ul>

{% endblock %}

注意:base.html相当于一个基础性的模板。我们写的时候先用extend表示继承,然后用标签提示每块是什么内容。比如被{%- block styles %}{%- endblock styles %}包裹的地方就是写css文件路径的地方(参见关键点3)。这个模板在类似这样的安装路径下:

D:\ProgramData\Anaconda3\Lib\site-packages\flask_bootstrap\templates\bootstrap

在这里插入图片描述

执行后控制台输出为:
在这里插入图片描述
访问 ip:8080/
在这里插入图片描述
访问 ip:8080/index,可以看到bootstrap已经用上了。
在这里插入图片描述

解决思路

首先构建一个form,提交按钮的click函数是:

$("#input-design-submit").click(function () {
	// get some data
    var seq = $(this).attr("data-seq"); 
    if (seq && seq.length>10 && seq.length < 10000) {
        $.ajax({
            type: 'POST',
            url: "/run_command",
            data: {
                sq: seq
            },
            success: function (resp) {
				// do sth, like unpack, parse
				var obj = jQuery.parseJSON(resp);
				var code = obj.code;
				...
			}
        });
    } else {
        return false;
    }
});

然后在后台写提交的路由:

curDir = os.getcwd()

@app.route('/run_command', methods=['POST'])
def run_command():
    if request.method == 'POST':
        #print(request.form)
        # make command
        cmdStr = "..."
        code = 1 # if fail, 0
        res = {}
        try:
            output = subprocess.check_output(cmdStr, shell=True, stderr=subprocess.STDOUT, universal_newlines=True)
            # parse output
           
        except subprocess.CalledProcessError as e:
            code = 0
		
		# add some data...
        res["code"] = code
        
        # convert to json string
        return json.dumps(res)
        

subprocess_check_output()参数说明:

  • command:这是一个字符串变量,包含要执行的命令。例如,command 可能是一个系统命令或者一个调用其他可执行文件的命令。
  • shell=True:这个参数告诉 subprocess 模块在一个 shell 中执行命令。如果设置为 False,则 command 将被当作一个可执行文件路径和参数列表来执行,而不是在 shell 中执行。
  • stderr=subprocess.STDOUT:这个参数指定将标准错误(stderr)重定向到标准输出(stdout)。这意味着标准错误将会和标准输出合并到一起,以便能够捕获所有输出。
  • universal_newlines=True:这个参数告诉 subprocess 将命令的输入和输出处理为文本模式而不是字节模式。这意味着执行结果将会是一个字符串,而不是一个字节串。
  • 返回值就是标准输出stdout。

关键点1:如何存放js文件

考虑到国内访问cdn可能会慢,所以把用到的js提前下载好,保存到本地。

首先需要指定static_folder

app = Flask(__name__, template_folder = curDir + "/static/templates", static_folder = curDir + "/static")

然后把*js放到指定好的位置。

在前端引用:

<!--script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script-->
<!--script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script-->
<script src="{{ url_for('static', filename='jquery.min.js') }}"></script>
<script src="{{ url_for('static', filename='bootstrap.min.js') }}"></script>

关键点2:动态更新图像文件的路径

这个小工具需要经过计算才能产生图像文件,所以在静态html里是不知道的。我采取的是路径映射的办法。

当前端发出post请求,收到回复后,动态加载一个<img>,大概写作:

const arr = ['<p><img src="', imgsrc, '" width="49%" alt="404"/></p><p>', desc, "</p>"]
$("#output-res").html(arr.join(''));
$("#output-res").show();

其中imgsrc和desc是两个经过解析得到的字符串;output-res是一个原本隐藏的div,需要加载图片的时候再显示。

假设imgsrc的格式是:"/output/" + name + ".gif",我的图像文件放在python文件根目录/static/output下,那么只要再写一个路径映射,利用flask包的send_from_directory函数就可以让图像正确显示了。

需要注意的是,send_from_directory()需要同时传递路径和文件名。

@app.route('/output/<filename>')
def uploaded_files(filename):
    # for img
    file_dir = curDir + '/static/output'
    return send_from_directory(file_dir, filename)

关键点3:如何放置css文件

放置在block head中:

{%- block head %}
    {%- block styles %}
	<!-- Bootstrap -->
	<!-- 在线的写法 -->
    <!--link href="{{bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap')}}" rel="stylesheet"-->
	<link href="{{ url_for('static', filename='bootstrap.min.css') }}" rel="stylesheet">
    <link href="{{ url_for('static', filename='style.css') }}" rel="stylesheet">
    {%- endblock styles %}
{%- endblock head %}

注意:如果想要在保留bootstrap格式的情况下增加新格式,需要保留第一个链接。此时css文件是放在主函数中写的、static路径下的。