Python 全栈系列38 - 搭建网站模板

it2025-01-18  37

说明

搭建网站模板的原因是未来需要快速的启动多个不同的web服务,建立一个基于自有算网的分布式web服务。

本篇梳理一下网站的模板(结构及静态资源),未来新的网站可以把模板拷贝过去再进行个性化调整就可以了。

1 结构

首先使用函数生成docker-compose项目结构。

import DataManipulation as dm # base_prj2 建立基础的web模板 dm.make_folder_struct(project_name='base_prj2', appname='base_web')

模板生成时,模型文件是空的,这里尝试使用jinja的方式写入。未来会形成几套模板,对应生成项目时就可以直接写入内容,表面手工的文件操作。(同理,系统的设置也将如此)

jinja的写入这里就不细说了,下次在别的地方专门说。

2 资源

资源的加载是有顺序的,本例用到了以下资源,都是耳熟能详的,就不解释了。

1 网页图标 <link rel="shortcut icon" href="/static/img/tem_logo.ico" type="image/x-icon"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> 2 Bootstrap4 <link rel="stylesheet" href="/static/vendor/Bootstrap/css/bootstrap.min.css"> <script src="/static/vendor/jquery/jquery.js"></script> <script src="/static/vendor/Bootstrap/js/bootstrap.min.js"></script> <script src="/static/vendor/Bootstrap/js/popper.min.js"></script>

-3 DataTables

<link rel="stylesheet" href="/static/vendor/DataTables/css/dataTable.css"> <script src="/static/vendor/DataTables/js/dataTable.js"></script> <!-- 3.1下载数据表的插件 --> <script src="/static/vendor/DataTables/js/dataTables.buttons.min.js"></script> <script src="/static/vendor/DataTables/js/buttons.html5.min.js"></script> <!-- 3.2下载数据表的插件 --> <script src="/static/vendor/ajax/pdfmake.min.js"></script> <!-- vfs_fonts要在pdfmake之后导入,否则会找不到字体 --> <script src="/static/vendor/ajax/vfs_fonts.js"></script> <script src="/static/vendor/ajax/jszip.min.js"></script> 4 inputfile <link href="/static/vendor/fileinput/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" /> <script src="/static/vendor/fileinput/js/plugins/sortable.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/js/fileinput.min.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/js/locales/zh.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/themes/explorer-fa/theme.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/themes/fa/theme.js"></script> 5 FontAweson 要放在inputfile之后 <link rel="stylesheet" href="/static/vendor/FontAwesome/css/font-awesome.min.css"> <link href="/static/vendor/fileinput/themes/explorer-fa/theme.css" media="all" rel="stylesheet" type="text/css" /> 6 echarts <script src="/static/vendor/echarts/echarts.min.js"></script>

3 基础网络服务

3.1 代码参考及解析

先参考一段代码 app. _init _.py

... def create_app(config_name): app = Flask(__name__) app.config.from_object(config[config_name]) config[config_name].init_app(app) # 为app增加功能 db.init_app(app) login_manager.init_app(app) mail.init_app(app) bootstrap.init_app(app) moment.init_app(app) # 注册蓝本 # 主函数 from .main import main as main_blueprint app.register_blueprint(main_blueprint) ...

project.config.py

# 数据库/Mail两个是刚性设置 ... class Config: SECRET_KEY = '加密的种子文本,最好从环境变量读入' # 数据库 SQLALCHEMY_COMMIT_ON_TEARDOWN = True # 类方法 # Config.init_app('') 直接调用 @staticmethod def init_app(app): print('*** creating app by Config class') ...

project.manage.py

... app = create_app('test') ... manager = Manager(app) if __name__ == '__main__': # 阻塞版 manager.run()

启动的结构为,进入project目录,执行命令(调试模式)。

python3 manager.py runserver -d 1 manage.py 包装了app再启动的2 app是通过init.py里面的create_app创建的3 init.py初始文件从config.py里读取了配置。因为此时启动的路径是config.py的同级目录,所以在init.py中是这样导入配置的4 在init.py文件中,子模块通过蓝图的方式挂到了app下面。 from config import config

Note:如果把app当成一个程序包就比较好理解了。比较特殊的是static和template两个文件夹,被flask固定使用了。

原来的flask服务里面加了很多组件,但是作为基础板块,我们都不需要加,只要留一个框子就可以了。

3.2 构建最精简的web结构

最终的项目结构如下

base_web ├── Dockerfile ├── app │ ├── __init__.py │ ├── main │ │ ├── __init__.py │ │ └── views.py │ ├── static │ │ ├── img │ │ └── vendor │ └── templates │ ├── base.html │ └── main ├── config │ └── config.py ├── data ├── entry_base_web.py ├── env │ ├── entrypoint.sh │ └── requirements.txt ├── log └── packages └── DataManipulation-0.1.16.10-py3-none-any.whl

我们按顺序进行说明(项目的依赖包,环境什么的就不说了)

1 首先我们得有一个入口函数entry_base_web.py 函数很简单,就是调用app(此时被视为一个函数包,因为有init文件,python会自动认定)中的create_app函数,生成实际运行的app,并且设置为调试模式。如果要切换环境什么的可以参考我的这篇文章进行微调就可以了。 from app import create_app if __name__ == '__main__': app = create_app('test') app.run(debug=True) 2 我们得要在app下面的__init__.py文件中创建create_app函数(当然另起一个文件也行) from flask import Flask # >>>>>>>>>>>>>>>>>>> 为了给Jinja导入bootstrap/wtf_form.html from flask_bootstrap import Bootstrap bootstrap = Bootstrap() # >>>>>>>>>>>>>>>>>>> 自定义通用函数包 import DataManipulation as dm # >>>>>>>>>>>>>>>>>>> 创建app的函数,可以用于以后灵活的加插件 def create_app(config_name): app = Flask(__name__) bootstrap.init_app(app) # 注册蓝本 # 1 默认一个主函数 from .main import main as main_blueprint app.register_blueprint(main_blueprint) return app # >>>>>>>>>>>>>>>>>>> 值错误的处理,暂时不定义 class ValidationError(ValueError): pass

在app包的初始化文件中,其实只是导入了Flask基本包,Bootstrap插件,以及我自定义的DataManipulation包。在create_app中我们引入了一个main主函数,避免网站起来什么都看不到。

3 创建main基本包。写入对应的__init__.py和views.py两个文件。前者负责沟通结构,把定义的视图函数传给main包,以便create_app通过蓝图注册。 __init__.py from flask import Blueprint # 优先指定蓝本 # main = Blueprint('main', __name__, url_prefix='/main') # main的目录就是根目录 main = Blueprint('main', __name__) from . import views

views.py

# 导入蓝图名称 from . import main # 导入最基本的必要功能 from flask import render_template, jsonify import DataManipulation as dm # 定义whoami @main.route('/whoami/', methods=['GET', 'POST']) def whoami(): res_dict ={} res_dict['hostname'] = dm.get_machine_hostname() res_dict['machine_ip'] = dm.get_machine_ip() res_dict['eid'] ='No Claimed' return jsonify(res_dict) # 定义基础页面 @main.route('/', methods=['GET', 'POST']) def index(): return render_template('/main/index.html')

一个是whoami函数,指明了本机的身份。会以接口形式返回结果。 另一个则是网站启动时显示的函数。里面用到了一个页面index.html

{% extends 'base.html'%} {%block navcontent%} <div class="container-fluid"><a xtype="a" class="navbar-brand" href="#">Base_Web</a> <ul xtype="h5_ele" class="navbar-nav navbar-top mr-5"> <li xtype="h5_ele" class="nav-item"><a xtype="h5_ele" href="{{url_for('main.index')}}" class="nav-link">主页</a> </li> </ul> </div> {%endblock%} {%block pagecontent%} <!-- 空白行作为间隔 --> <div class="m-5"></div> <div class="row"> <div class="col md-12"> <div xtype="h5_ele" class="jumbotron"> <h1>BaseWeb</h1> <hr> <p> BaseWeb</p> <p> BaseWeb</p> <p> BaseWebBaseWebBaseWebBaseWebBaseWebBaseWeb</p> <p> BaseWebBaseWebBaseWebBaseWebBaseWebBaseWeb</p> <p> BaseWebBaseWebBaseWebBaseWebBaseWebBaseWeb</p> </div> </div> </div> <!-- 空白行作为间隔 --> <div class="m-5"></div> <div class="row"> <div class="col md-12"> <img src="static/img/main/test1.jpg" alt="" style="width: 100%;"> </div> </div> {%endblock%}

页面继承了基础的页面 base.html并随便写了些内容。

<!DOCTYPE html> <html> {% import "bootstrap/wtf.html" as wtf %} {%block head%} <!-- 1 网页图标 --> <link rel="shortcut icon" href="/static/img/tem_logo.ico" type="image/x-icon"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 2 Bootstrap4 --> <link rel="stylesheet" href="/static/vendor/Bootstrap/css/bootstrap.min.css"> <script src="/static/vendor/jquery/jquery.js"></script> <script src="/static/vendor/Bootstrap/js/bootstrap.min.js"></script> <script src="/static/vendor/Bootstrap/js/popper.min.js"></script> <!-- 3 DataTables --> <link rel="stylesheet" href="/static/vendor/DataTables/css/dataTable.css"> <script src="/static/vendor/DataTables/js/dataTable.js"></script> <!-- 3.1下载数据表的插件 --> <script src="/static/vendor/DataTables/js/dataTables.buttons.min.js"></script> <script src="/static/vendor/DataTables/js/buttons.html5.min.js"></script> <!-- 3.2下载数据表的插件 --> <script src="/static/vendor/ajax/pdfmake.min.js"></script> <!-- vfs_fonts要在pdfmake之后导入,否则会找不到字体 --> <script src="/static/vendor/ajax/vfs_fonts.js"></script> <script src="/static/vendor/ajax/jszip.min.js"></script> <!-- 4 inputfile --> <link href="/static/vendor/fileinput/css/fileinput.min.css" media="all" rel="stylesheet" type="text/css" /> <!-- FontAweson 要放在inputfile之后 --> <link rel="stylesheet" href="/static/vendor/FontAwesome/css/font-awesome.min.css"> <link href="/static/vendor/fileinput/themes/explorer-fa/theme.css" media="all" rel="stylesheet" type="text/css" /> <script src="/static/vendor/fileinput/js/plugins/sortable.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/js/fileinput.min.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/js/locales/zh.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/themes/explorer-fa/theme.js" type="text/javascript"></script> <script src="/static/vendor/fileinput/themes/fa/theme.js"></script> <!-- 5 echarts--> <script src="/static/vendor/echarts/echarts.min.js"></script> <title>BaseWeb</title> {%endblock%} {%block nav%} <nav class="navbar navbar-expand-md bg-dark navbar-dark"> {%block navcontent%} <!-- Brand --> <a class="navbar-brand" href="{{url_for('main.index')}}">BaseWeb</a> {%endblock%} </nav> {%endblock%} {%block body%} <body> <div id="a0"></div> <div class="container"> {%for message in get_flashed_messages()%} <div class='alert alert-warning'> <button type='button' class='close' data-dismiss='alert'> &times;</button> {{message}} </div> {%endfor%} {%block pagecontent%} <!-- row1 --> <div class="row"> <div class="col"> First Row First Col </div> </div> {%endblock%} </div> </body> {%endblock%} </html>

base.html导入了网站所需的资源。到这里就完成了最简网站的所有配置,可以启动了。切换到项目所在的文件夹,执行:

python3 entry_base_web.py

在浏览其中访问,可以看到后端在第一次访问时载入了资源

前端的效果 后面就可以在这个基础上进行各种修改了。

最新回复(0)