说明

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

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

1 结构

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

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

python建站教程 python 建站模板_css


模板生成时,模型文件是空的,这里尝试使用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__.pyviews.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函数,指明了本机的身份。会以接口形式返回结果。

python建站教程 python 建站模板_bootstrap_02


另一个则是网站启动时显示的函数。里面用到了一个页面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'> ×</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

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

python建站教程 python 建站模板_css_03

前端的效果

python建站教程 python 建站模板_css_04


后面就可以在这个基础上进行各种修改了。