文章目录

  • 配置MySQL Workbench
  • Git仓库
  • 创建虚拟环境
  • 配置解释器
  • 创建项目
  • 路由查找
  • 使用Postman发送请求
  • 提交到Git
  • 配置文件的拆分
  • 核心对象拆分
  • 视图文件注册到蓝图
  • 整合router的注册
  • 蓝图注册到app
  • json数据的展示
  • 新闻资讯站点示例
  • Flask数据模型
  • ORM
  • sqlite本地文件数据库(本地测试使用)
  • 数据模型定义方法2
  • Flask命令行
  • 使用MySQL Workbench 插入语句
  • 数据库增删查改
    • 查询
    • 增加
    • 修改
    • 删除
  • api 统一标准返回
  • flask_marshmallow模块 序列化
  • mvc、mtv模式、前后端分离
  • RestFul API 表现层状态转化
  • 自带的序列化工具
  • 参数解析
  • CMDB
  • CMDB数据模型建立
    • 一对多关系
    • 多对多关系
    • 一对一关系
  • 获取服务器数据接口
  • 嵌套蓝图
  • 调用接口获取服务器数据
  • pycham 编辑远程脚本
  • 优化:增加API授权

个人博客
https://blog.csdn.net/cPen_web

配置MySQL Workbench


create database flask_app;

linux mysql 下 设置其他主机可以连接

UPDATE mysql.user SET Host='%' WHERE Host='localhost' AND User='root';
FLUSH PRIVILEGES;

Git仓库

·创建git仓库
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app
$ pwd
/e/web_cpen/flask_proj/flask_app
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app
$ git init              #注:初始化git仓库(把它变成git仓库)
Initialized empty Git repository in E:/web_cpen/flask_proj/flask_app/.git/
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
·添加.gitignroe配置(venv、logs等目录)
$ vim .gitignore        #注:文件不上传
*.pyc
.idea/
*.log
·提交一个版本(初始化完成)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git add --all
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git commit -m "add ignore"
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git remote -v         #注:没有远程仓库连接
#步骤:在码云上创建新仓库cpen_flask_app
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git config --global user.name "cPen"
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git config --global user.email "1533431376@qq.com"
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git remote add origin https://gitee.com/cPen_web/cpen_flask_app.git
#注:把本地推送到远端+添加别名
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git push origin master

创建虚拟环境

·创建虚拟环境(使用git-bash)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ python -m venv venv           #注:创建虚拟环境
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ source venv/Scripts/activate  #注:进入虚拟环境
(venv)
·安装Flask
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ pip install Flask             #注:安装Flask
(venv)

配置解释器



点ok

虚拟环境下(venv)

flask 基于werkzeug工具箱和jinja2模板引擎开发的一个轻量级web框架

创建项目

#创建第一个flask项目
from flask import Flaskapp = Flask(__name__)   #实例化对象app.run()
#创建第一个flask项目
#flask 基于werkzeug工具箱和jinja2模板引擎开发的一个轻量级web框架#导入flask的核心对象
from flask import Flask#实例化对象,传入一个名字,一般就用__name__
app = Flask(__name__)#默认endpoint就是函数名,index
#method指定请求方法类型 默认为GET
#@app.route("/")
@app.route("/", methods=["POST","GET"]) #注:支持POST、GET请求,传入列表
def index():return "this is ok"#设置路由
#@app.route("/index")
#def index2(username):
def index2():#return "this is index"
#return f"args {username} is ok"return f"args is ok"@app.route("/index3")
def index3():return "hello world"#app.add_url_rule("/index", view_func=index2) #第二种添加路由的方法
#app.add_url_rule("/index", view_func=index2, endpoint="index3")
#构造动态url,让url传递参数
#app.add_url_rule("/index/<string:username>", view_func=index2) #注:传入参数
#app.add_url_rule("/index/<string:username>", view_func=index2,methods=["POST"])
app.add_url_rule("/index/", view_func=index2,methods=["POST"])
#注:支持POST请求
#注:用于学生管理系统,在url里传递id; 删除修改操作#打开调试模式
#app.debug = True
#app.run()
app.run(host="0.0.0.0",port=5555,debug=True) #注:第二种方式 调试模式+绑定5555端口,主机#点击结果为 this is ok
#点击结果为 this is index
#127.0.0.1 - - [11/Dec/2020 16:46:20] "GET / HTTP/1.1" 200 -
#------------------------------------------------------------
#127.0.0.1:5000/index/cp
#args cp is ok#注:默认GET请求
#注:405 请求的方式不对 405 Method Not Allowed

路由查找

#flask会维护两张表
#一张表记录 从url到endpoint的映射关系   url_map
#一张表记录 从endpoint到func的映射关系  view_functions#endpoint在flask路由表中具有唯一性
#endpoint没有指定,默认就是函数名

使用Postman发送请求

提交到Git

15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ cd flask_app/
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git add server.py
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git commit -m "flask_01"
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ git push origin master

配置文件的拆分

conf目录 --> settings.py文件
Host = "0.0.0.0"
Port = 8000
Debug = True
HOST = "0.0.0.0"
PORT = 8000
DEBUG = True

方法1:
server.py文件

from conf.settings import *
app.run(host=Host,port=Port,debug=Debug)

方法2:
server.py文件

app.config.from_object('conf.settings')app.run(host=app.config["HOST"],port=app.config["PORT"],debug=app.config["DEBUG"])

核心对象拆分

app.py文件

import os
from flask import Flaskprint(os.environ)def create_app(config=None):app = Flask(__name__)# load default configurationapp.config.from_object('conf.settings')# app.config.from_object('config.secure')# load environment configuration# FLASK_CONF="/path/to/config_dev.py"# FLASK_CONF="/path/to/config_prod.py"# 也可以根据系统环境变量,加载不同的配置文件if 'FLASK_CONF' in os.environ:app.config.from_envvar('FLASK_CONF')# load app sepcified configurationif config is not None:if isinstance(config, dict):app.config.update(config)elif config.endswith('.py'):app.config.from_pyfile(config)return app

server.py文件

from app import create_appapp = create_app()

router目录 --> view01.py文件

#注:(这种写法不好,router目录下 多个文件不符合美感,引入下面的蓝图)
from app import create_app
app = create_app()@app.route("/", methods=["POST","GET"])
def index():return "this is ok"# @app.route("/index")
def index2():return f"args is ok"@app.route("/index3")
def index3():return "hello world"
#构造动态url,让url传递参数
app.add_url_rule("/index/", view_func=index2,methods=["POST"])

server.py文件

from router.view01 import app

环境变量

>>> import os
>>> print(os.environ)      #注:Python里查看系统环境变量
[root@localhost ~]# env        #注:linux里查看环境变量Linux里添加(定义)环境变量
[root@localhost ~]# vim .bashrc
FLASK_CONF=/home/sanchuang/flask_config.py
export FLASK_CONF
[root@localhost ~]# vim /home/sanchuang/flask_config.py
[root@localhost ~]# env
FLASK_CONF=/home/sanchuang/flask_config.py
>>> import os
>>> print(os.environ)
environ({… 'FLASK_CONF': '/home/sanchuang/flask_config.py'…})

当前
server.py文件

from app import create_app
app = create_app()app.run(host=app.config["HOST"],port=app.config["PORT"],debug=app.config["DEBUG"])

app.py文件

import os
from flask import Flaskdef create_app(config=None):app = Flask(__name__)# load default configurationapp.config.from_object('conf.settings')# app.config.from_object('config.secure')# load environment configuration# FLASK_CONF="/path/to/config_dev.py"# FLASK_CONF="/path/to/config_prod.py"# 也可以根据系统环境变量,加载不同的配置文件if 'FLASK_CONF' in os.environ:app.config.from_envvar('FLASK_CONF')# load app sepcified configurationif config is not None:if isinstance(config, dict):app.config.update(config)elif config.endswith('.py'):app.config.from_pyfile(config)return app

conf目录 --> setting.py文件

HOST = "0.0.0.0"
PORT = 8000
DEBUG = True

视图文件注册到蓝图

router目录 --> view01.py文件

from flask import Blueprintview01_bp = Blueprint('view01',__name__,url_prefix='/view01/')@view01_bp.route("/index", methods=["POST","GET"])
def index():return "this is blueprint"

router目录 --> view02.py文件

from flask import Blueprintview02_bp = Blueprint('view02',__name__,url_prefix='/view02/')@view02_bp.route("/", methods=["POST","GET"])
def index():return "this is view02 blueprint"

整合router的注册

router目录 --> init.py文件

from .view01 import view01_bp
from .view02 import view02_bpdef init_app(app):app.register_blueprint(view01_bp)app.register_blueprint(view02_bp)

server.py文件

#不建议这样写
from app import create_app
from router import init_appapp = create_app()
init_app(app)app.run(host=app.config["HOST"],port=app.config["PORT"],debug=app.config["DEBUG"])

蓝图注册到app

app.py文件

import os
from flask import Flaskdef create_app(config=None):app = Flask(__name__)# load default configurationapp.config.from_object('conf.settings')# app.config.from_object('config.secure')# load environment configuration# FLASK_CONF="/path/to/config_dev.py"# FLASK_CONF="/path/to/config_prod.py"# 也可以根据系统环境变量,加载不同的配置文件if 'FLASK_CONF' in os.environ:app.config.from_envvar('FLASK_CONF')# load app sepcified configurationif config is not None:if isinstance(config, dict):app.config.update(config)elif config.endswith('.py'):app.config.from_pyfile(config)#注册蓝图               #注:改的地方from router import init_appinit_app(app)return app

主文件 server.py

from app import create_appapp = create_app()app.run(host=app.config["HOST"],port=app.config["PORT"],debug=app.config["DEBUG"])
#结果为
127.0.0.1:8000/view01/index     this is blueprint
127.0.0.1:8000/view02/          this is view02 blueprint

api Application Programming Interface 应用程序接口

前后端分离:前后端代码独立
验证登录成功/失败,后端 flask做,前端使用ajax技术发起请求,请求后端flask的接口api,验证返回结果


前后端分离 好处:页面分开,各自写各自的页面,统一调用接口就可以了
前后端隔离 好处:可以并行开发,增加开发效率,增加人力资源的利用

json数据的展示

router目录 view01.py文件下

from flask import Blueprint
import json
view01_bp = Blueprint('view01',__name__,url_prefix='/view01/')@view01_bp.route("/index", methods=["POST","GET"])
def index():dict1 = {"name":"wen","age":18,"sex":"女"}return json.dumps(dict1)


获取数据成功

新闻资讯站点示例

静态页面展示
步骤1:创建static、templates目录

步骤2:
将index.html放到 templates下面 (模板文件,要返回的页面内容)
将css、images、js放到static下面 (静态资源)

步骤3:导入render_template模块,进行访问
router目录 view02.py文件下

from flask import Blueprint, render_templateview02_bp = Blueprint('view02',__name__,url_prefix='/view02/')@view02_bp.route("/index", methods=["POST","GET"])
def index():return render_template("index.html")


结果 127.0.0.1:8000/view02/index 访问成功,页面图片加载不出来


步骤:构造url (需要导入url_for模块)

from flask import Blueprint, url_for
print( url_for("static",filename="/view02/images/01.jpg"))
#注:前面static和后面/view02/images/01.jpg 拼接

步骤:
((css|js|images).*?(css|js|jpg|png|gif|bmp))
{{ url_for(‘static’, filename=’$1’) }} #注:2个{}是jinja2的语法
批量匹配和替换 pycharm里面 ctrl+r
然后勾选 match case 和 regex 支持正则

在html里面使用Python语法,使用了jinja2引擎,所以{{ url_for(‘static’, filename=’$1’) }}
有2个括号,$1表示最前面的那个组(最外面的括号)

index.html不是纯粹的网页模板,使用了jinja2模板引擎 渲染

现在静态页面都是写死了的,所以 写到数据库里。现在假设数据放在字典里,如何把HTML和Python结合起来。templates下 把模板和数据做结合,使用jinja2模板引擎

router目录 view02.py文件下

from flask import Blueprint, render_template
view02_bp = Blueprint('view02',__name__,url_prefix='/view02/')
@view02_bp.route("/index", methods=["POST","GET"])
def index():content = {"title":"标题一","childtitle":"标题二"}#返回html前将模板和数据做一个结合result_html = render_template("index.html", content=content)  #注:接收可变成长关键字参数return result_html


因为没学数据库,所以数据先放在字典里

templates目录 index.html文件下
#注:使用jinja2的语法 {{ content.title }} {{ content.childtitle }}

渲染成功

#注:更倾向于 字典解包

router目录 view02.py文件

templates目录 index.html文件

#注:渲染成功

Flask数据模型

Python3 MySQL 数据库连接 执行SQL语句 在数据库里面运行

[root@cPen_aliyun ~]# pip3 install PyMySQL
>>> import pymysql
>>> conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",passwd="******",database="flask_app")
>>> conn
<pymysql.connections.Connection object at 0x7fdb4ccfdc18>
>>> cursor = conn.cursor()    #注:创建游标,操控数据库的对象,建立在连接上面的
>>> cursor.execute("select version()")   #注:在这个对象上执行语句
1
>>> data = cursor.fetchone()          #注:返回的结果就是fetchone
>>> data
('5.7.31',)
#注:fetchone抓取一行,fetchall抓取全部

MySQL WorkBench里 建表操作

use sanchuang;           #注:进入库
create table stu (          #注:创建表
id int not null primary key,
name varchar(128),
sex varchar(64),
age int);

步骤:stu右键 Send to SQL Editor --> 右边 Insert Statement
#注:向表里插入数据

INSERT INTO `sanchuang`.`stu`
(`id`,
`name`,
`sex`,
`age`)
VALUES
(<{id: }>,
<{name: }>,
<{sex: }>,
<{age: }>);
(1,          #注:向表插入数据
"wy",
"f",
18);

步骤:stu右键 Select Rows (第一行) 查看表数据

>>> conn = pymysql.connect(host="127.0.0.1",port=3306,user="root",passwd="******",database="sanchuang")
>>> cursor = conn.cursor()
>>> cursor.execute("select * from stu")      #注:从stu表里查询所有的记录
2
>>> data = cursor.fetchone()      #注:fetchone抓取一行,fetchall抓取全部
>>> print(data)
(1, 'wy', 'f', 18)
>>> data = cursor.fetchone()
>>> print(data)
(2, 'wy2', 'f', 18)

#注:MySQL WorkBench里 设置为默认库的操作
Sanchuang 右键 --> Set as Default Schema 设置为默认库 (sanchuang字体会加粗)

ORM

ORM,即Object-Relational Mapping(对象关系映射)
引入ORM,中间层,帮我们去连数据库,我们只需要操纵中间层ORM,不需要我们去关注 数据库的连接和管理。
#步骤:安装模块 (pycharm里执行)

pip install flask-sqlalchemy

#步骤:pycharm里面 创建 model目录
#步骤:model目录下 创建user.py、base.py、init.py模块

在model目录 base.py模块下 创建ORM对象 (创建实例)
#注:考虑到后期models拆分,单独创建ORM对象: models/base.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()from . import user            #注:把定义好的模型导入

#步骤:定义数据模型
在model目录 user.py模块下 导入db 定义数据模型

from .base import dbclass Stu(db.Model):         #注:继承db的Model类  它已经是有映射关系的类了__tablename__ = "stu"     #注:创建的数据模型 stu,映射到数据库里的stu表id = db.Column(db.INTEGER,primary_key=True)name = db.Column(db.String)sex = db.Column(db.String)age = db.Column(db.INTEGER)
#注:对象关系映射,操纵这个类就是操纵这个数据库了

在model目录 init.py模块下

from .base import dbdef init_app(app):db.init_app(app)#db.create_all(app=app)   #注:如果数据库里没有那个表就创建

在app.py文件下

#注册初始化数据模型
from model import init_app
init_app(app)

步骤:数据库的连接
#注:可以在实例化之后,修改SQLALCHEMY_DATABASE_URI 属性,或者在实例化之前,继承Flask类时,重写__init__

在conf目录 settings.py文件下

SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:******@47.110.144.55:3306/sanchuang"
app.py 实例化对象时  会读取这个文件里的参数,对属性进行修改

在router目录 view01.py文件下

from flask import Blueprint, url_for
import json
from model.user import Stu              #注:加这一句view01_bp = Blueprint('view01',__name__,url_prefix='/view01/')@view01_bp.route("/index", methods=["POST","GET"])
def index():user_info = Stu.query.all()            #注:改这里return user_info       #注:Stu.query.all()查询语句,查询所有的字段。必须得遵循一定的规范

pycharm里安装 PyMySQL

pip install PyMySQL

步骤:Postman访问127.0.0.1:8000/view01/index
显示TypeError,因为查找的 Stu.query.all() 是对象,不能直接做HTML的返回。
可以为对象转换格式,最好转换成string类型格式去输出
TypeError: The view function did not return a valid response. The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a list.

可以为对象转换格式,最好转换成string类型格式去输出
方法1转换成字典
在model目录 user.py文件下
#注:重写__init__方法,添加新方法 to_json

from .base import dbclass Stu(db.Model):__tablename__ = "stu"id = db.Column(db.INTEGER,primary_key=True)name = db.Column(db.String)sex = db.Column(db.String)age = db.Column(db.INTEGER)def __init__(self,id,name,sex,age):  #注:重写__init__方法self.id = idself.name = nameself.sex = sexself.age = agedef to_json(self):        #注:添加 to_json方法return {"id":self.id,"name":self.name,"sex":self.sex,"age":self.age}

在router目录 view01.py文件下

from flask import Blueprint, url_for
import json
from model.user import Stuview01_bp = Blueprint('view01',__name__,url_prefix='/view01/')@view01_bp.route("/index", methods=["POST","GET"])
def index():user_info = Stu.query.all()    #注:Stu.query.all() 查询Stu里面所有的记录的字段#注:对象是保存在内存里的,不能直接返回,HTML不认识result_list = []         #注:修改的地方 for user in user_info:      #注:循环获取它里面的每一个对象result_list.append(user.to_json())  #注:直接添加 user.to_json(),把它转换成字典#注:最后得到的是 列表里面包字典 符合  json格式的字符串return json.dumps(result_list)    #注:所有返回json格式

步骤:Postman访问
127.0.0.1:8000/view01/index #注:得到的结果就是数据库里的东西

sqlite本地文件数据库(本地测试使用)

flask_app --> conf目录 --> setting.py文件

import os
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
print(os.path.dirname(__file__))
#注:获取上层路径    conf
# E:/web_cpen/flask_proj/flask_app/conf
print(os.path.dirname(os.path.dirname(__file__)))   #注:flask_app的绝对路径
##注:获取上上层路径 flask_app
# E:/web_cpen/flask_proj/flask_app
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
print(os.path.join(basedir, 'data.sqlite'))
#结果 E:\web_cpen\flask_proj\flask_app\data.sqlite
import os
basedir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
#print(os.path.dirname(os.path.dirname(__file__)))#sqlite的连接方式
#sqlite 本地文件数据库 一般用于测试
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'data.sqlite')
print(os.path.join(basedir, 'data.sqlite'))

flask_app --> model目录 --> __init__文件

from .base import dbdef init_app(app):db.init_app(app)db.create_all(app=app)        #注:加这一句  自动去数据库里创建表 (这个表和)#注:如果是连接数据库,更改表需要考虑 这个用户 有没有权限#注:用户如果 有权限 可以这样创建表flask_app --> server.py文件 运行
#注:生成了data.sqlite文件
#注:将生成的data.sqlite文件拖过去


步骤:点 + 号 --> Data Source --> Sqlite(Xerial)

步骤:点download 下载插件

显示成功

Database 点 + 号 --> Data Source --> 添加MySQL

点 + 号插入数据

数据模型定义方法2

flask_app --> model目录 --> user.py文件

from sqlalchemy import Column, String        #注:加这句话  第二种模型的定义
from .base import dbclass Stu(db.Model):__tablename__ = "stu"id = db.Column(db.INTEGER,primary_key=True)name = db.Column(db.String,unique=True)  #注:唯一索引sex = db.Column(db.String)age = db.Column(db.INTEGER)email = Column(String)        #注:加这句话 第二种模型的定义,就不用写db 了

flask_app --> router目录 --> view01.py

from flask import Blueprint, url_for
import json
from model.user import Stuview01_bp = Blueprint('view01',__name__,url_prefix='/view01/')@view01_bp.route("/get", methods=["POST","GET"])  #注:添加的部分
def get():                  #注:添加的部分user_info = Stu.query.all()result_list = []for user in user_info:result_list.append(user.to_json())#print( url_for("static",filename="/view02/images/01.jpg"))return json.dumps(result_list)

flask_app --> model目录 --> user.py文件下 #注:新增email

from sqlalchemy import Column, String
from .base import dbclass Stu(db.Model):__tablename__ = "stu"id = db.Column(db.INTEGER,primary_key=True)…………email = Column(String)def __init__(self,id,name,sex,age,email):…………self.email = emaildef to_json(self):return {…………"email":self.email}

Flask命令行

创建文件:跟server.py同级的 manage.py文件 flask_app --> manage.py文件

Terminal命令行 安装:pip install flask_script

Flask的Web开发服务器支持很多启动设置选项,但只能在脚本中作为参数传给app.run()函数。这种方 式很不方便,传递设置选项的理想方式是使用命令行参数

flask_app --> manage.py文件
#注:输入如下 使用flask命令行(manage类) 去管理app

#flask命令行
from flask_script import Manager
from app import create_app
app = create_app()manager = Manager(app)
if __name__ == '__main__':manager.run()

为了让Flask的启动更加灵活,可以使用Flask-Script中自带的runserver
#注:命令行还可以操控数据库,不推荐以前使用的 flask_app --> app.py 文件下的 create_app() 操作

步骤:终端启动 在gitbash里面运行 python manage.py runserver -d -h 0.0.0.0 -p 5000

#注:-d 进入debug模式 -h hostname -p 端口
#注:先进入虚拟环境,再执行命令
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ source venv/Scripts/activate          #注:source加载环境变量  进入虚拟环境
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ cd flask_app/
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ ls
__pycache__/  conf/        manage.py  router/    static/
app.py        data.sqlite  model/     server.py  templates/
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ python manage.py runserver -d -h 0.0.0.0 -p 8000      #注:执行此命令
#注:runserver 运行服务* Serving Flask app "app" (lazy loading)* Environment: production
…………* Debugger is active!* Debugger PIN: 637-344-130* Running on http://0.0.0.0:8000/ (Press CTRL+C to quit)#注:命令行还可以操控数据库,不推荐以前的create_app操作

Terminal 命令行 安装 flask_migrate

(venv) E:\web_cpen\flask_proj\flask_app>pip install flask_migrate

flask_app --> manage.py文件 导入
步骤:数据库迁移: manage.py

from flask_migrate import Migrate, MigrateCommand
from model import db
#注:因为db写在了__init__.py里,所有可以直接导入
#注:如果写在 model --> user.py  则from model.user import *
#flask命令行
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand       #注:添加的地方
from model import db                    #注:添加的地方
from app import create_app
app = create_app()manager = Manager(app)# 创建db管理工具 => app, db         #注:添加这几句
# 注意,如果是sqlite数据库需要修改
migrate = Migrate(app, db)# 添加迁移脚本的命令到manager中
manager.add_command('db', MigrateCommand) #注:添加命令  添加的命令if __name__ == '__main__':manager.run()

Gitbash操作

#注:在 E:\web_cpen\flask_proj\flask_app 右键 Git bash here (又一个gitbash界面)15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ source ../venv/Scripts/activate       #注:进入虚拟环境
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ ls
__pycache__/  conf/        manage.py  router/    static/
app.py        data.sqlite  model/     server.py  templates/
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ python manage.py db init          #注:初始化操作
…………
'E:\\web_cpen\\flask_proj\\flask_app\\migrations\\alembic.ini' before proceeding.
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$

初始化后pycharm界面 生成 migrations目录 记录mysql的版本。可以删除,每次init初始化后会自动生成

在gitbash里面操作

#注:执行 python manage.py db migrate -m "01"
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ python manage.py db migrate -m "01"     #注:-m “01”是执行的注释

产生文件: migrations目录 --> version -->63477……文件
#注:对数据库的操作都在这个文件里 #注:migrate 迁移

15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ python manage.py db upgrade

出错了

步骤:
1、删除 migrations目录
2、在terminal命令行 重新执行3步

(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db init
(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db migrate -m "01"
(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db upgrade

#结果:一样的错误,因为以前创的表 长度 和现在初始化的长度不一样
#注:string类型映射在里面是varchar类型,所以需要指定长度
#报错显示:… sqlalchemy.exc.CompileError: VARCHAR requires a length on dialect mysql
#注:所以string类型需要指定长度 或者 删除mysql里的表

string类型需要指定长度
flask_app --> model目录 --> user.py文件下

class Stu(db.Model):__tablename__ = "stu"id = db.Column(db.INTEGER,primary_key=True)name = db.Column(db.String(64),unique=True)       #注:添加数字sex = db.Column(db.String(64))           #注:添加数字age = db.Column(db.INTEGER)email = Column(String(128))          #注:添加数字

#注:本地 migration --> versions 记录它的 版本号,同时在数据库里创建一个记录版本号的表。每一次做变更 对比版本号。版本号有偏差 ,提交不上来。把alembic_version表和migrations都删了,再重新init 重新提交


#注:version_num 只显示 最近一次的版本

模型 新增一列 add_time

import datetime                      #注:加这句话
from sqlalchemy import Column, String, DateTime         #注:加这句话
from .base import dbclass Stu(db.Model):__tablename__ = "stu"id = db.Column(db.INTEGER,primary_key=True)name = db.Column(db.String(64),unique=True)sex = db.Column(db.String(64))age = db.Column(db.INTEGER)email = Column(String(128))add_time = Column(DateTime, default=datetime.datetime.now()) #注:加这一句话 (上传的话 不传add_time 自动添加datetime)

#注:不需要 init 初始化版本了,以及有版本了,重复后面2步操作

(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db migrate -m "02"
(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db upgrade

#注:这样 表里面就有了 add_time
#注:你有这个写的权限 就可以这么做了。 在线上 编写程序可以,但工作时不可以 需要向DBA申请权限

回滚版本 使用语句: python manage.py db downgrade (upgrade) 版本号

使用MySQL Workbench 插入语句

#步骤:点击左上角 +SQL 新增一个SQL页

desc stu;                    #注:查看表结构


#注:数据库里给的 add_time default 是NULL,默认给NULL值。除主键外 每个字段 Null 都可以为空(YES)。auto_increment 自增。

insert into stu(id,name,sex,age) values(3,"wy3","f",19)  #注:插入数据

#注:左边的 id,name,sex,age 表示要插入的 字段。只对这四个字段插入数据

select * from stu    #注:查看表数据


#注:只插入了4个数据

insert into stu(name,sex,age) values("wy2","f",19)       #注:id为2  因为会自增auto_increment

#注:id不插入的情况:成功了,id 会自增 (auto increment),id不为空 (NULL NO)

#注:id自增1

#注:add_time 在python给的 default值 ,是中间ORM对象关系映射 中间那层的(python的),不是数据库的
这个datetime是Python的 ORM 的值,不是数据库的。直接直接操控数据库,数据库没有default 这个值

数据库增删查改

requests属性
args 接收请求的url参数 dict
form 记录请求中的表单数据 dict
headers 记录请求中的报文头
method 记录请求中http的使用方法 string
url 记录请求的url地址

查询

(venv) E:\web_cpen\flask_proj\flask_app>python manage.py shell
#注:进入当前flask上下文环境
>>> from model.user import Stu     #注:把model导入进来,使用这个模型
>>> user_info = Stu.query.all()
#注:all查询出来的是列表对象,每一项 就是这个表的数据
>>> user_info
[<Stu 1>, <Stu 2>]
>>> for i in user_info:
...     print(i)
...
<Stu 1>                       #注:每个对象都是数据库 表的实例 必须转换成json格式
<Stu 2>
#注:Stu.query.all()生成类似列表一样的东西,列表里面的 <Stu 1> 和 <Stu 2>,每一个对象 就是 每一行数据 (刚才新增的2行数据)


#注:在pycharm里 可以这样 添加数据库 数据

#注:这时 Stu.query.all() 列表里面就有3个了,每一行数据 都是一个数据库对象
#注:捞取这个 数据库的内容 不能直接返回。因为返回的是网页内容,数据库对象 网页识别不了,http协议不支持 展示不了。所以把它转化为 json格式

request 获取请求里的信息

#注:捞取这个 数据库的内容 不能直接返回。因为返回的是网页内容,数据库对象 网页识别不了,http协议不支持 展示不了。所以把它转化为 json格式。for 循环取的是它的每一个对象,to_json方法 把它 转换成 字典,加入到列表里面。列表里面包字典 符合json格式,使用json.dumps() 把它转化成json格式的字符串 ,再返回过去

#注:如果只想 获取(get) 某一个 (比如只想get id为1的详细信息),这个请求 应该由客户端告诉我,可以在url 后面传递 参数 (?号之后 都是它传递的参数,可以传递多个参数,用&号分割)

flask_app --> router目录下 --> view01.py文件里
#注:request.args 获取的参数 是一个字典 {“id”:”1”}

#注:导入flask 里面 request对象 ,获取url 里面的参数( request 获取请求里的信息)

from flask import Blueprint, url_for,request     #注:改的地方
import json
from model.user import Stuview01_bp = Blueprint('view01',__name__,url_prefix='/') #注:‘/’改的地方@view01_bp.route("/get", methods=["POST","GET"])
def get():                      #注:改的地方,逻辑id = request.args.get("id","all")          #注:这样获取 传递进来的idresult_list = []                 #注:使用get 万一没有传递id,给all值#注:列表放到外面  是为了兼容if id == 'all':                    #注:如果传递进来的id=all时user_info = Stu.query.all()           #注:all  查询所有 数据库记录的对象for user in user_info:      #注:Stu.query.all()生成类似列表一样的东西result_list.append(user.to_json())  #注:这里 将表里的实例转换成json格式 才能识别else:user_info = Stu.query.get(int(id))   #注:Stu.query.get 获取 id的数据,把id转换成int类型#注:使用get去 获取(查询) 它的主键 result_list.append(user_info.to_json())return json.dumps(result_list)
127.0.0.1:8000/get
127.0.0.1:8000/get?id=2



或者:在路由那里传递参数 <>括起来

flask_app --> router目录下 --> view01.py文件里

from flask import Blueprint, url_for,request
import json
from model.user import Stuview01_bp = Blueprint('view01',__name__,url_prefix='/')@view01_bp.route("/get/<id>", methods=["POST","GET"])  #注:这里
def get(id):                    #注:这里#id = request.args.get("id","all")result_list = []if id == 'all':user_info = Stu.query.all()for user in user_info:result_list.append(user.to_json())else:user_info = Stu.query.get(int(id))result_list.append(user_info.to_json())return json.dumps(result_list)Postman里面
127.0.0.1:8000/get/1
127.0.0.1:8000/get/all


#注:按条件查询 (过滤查询 Stu.query.filter_by(name=‘wy’).all())

#注:在terminal命令行输入

>>> stu1 = Stu.query.filter_by(name='wy').all()
>>> stu1
[<Stu 1>]
>>> stu1 = Stu.query.filter_by(age=19).all()
>>> stu1
[<Stu 1>, <Stu 2>]
>>> stu1 = Stu.query.filter_by(age=19).first()
>>> stu1
<Stu 1>
#注:all 查询所有,first查询第一个。all返回列表,first返回对象
>>> stu1 = Stu.query.filter(Stu.age<20).all()  #注:查找年龄小于20的
>>> stu1
[<Stu 1>, <Stu 2>]select * from stu limit 1            #注:限制查询1条数据
select * from stu limit 1 offset 1     #注:offset 偏移  从第2个查

增加

选择 Body --> form-data 表单型数据 POST方法:提交方法

#注:表单型数据做提交

flask_app --> router目录 --> view01.py文件

#注:增加的部分
@view01_bp.route("/add", methods=["POST", "GET"])
def add():data = request.form          #注:核心点return json.dumps(data)

postman下

完善

@view01_bp.route("/add", methods=["POST", "GET"])
def add():data = request.formuser = Stu(data["id"],  #注:实例化对象,生成一个数据库对象data["name"],data["sex"],data["age"],data["email"])db.session.add(user)    #注:传的参数就是 生成的数据库对象db.session.commit()     #注:提交return json.dumps(data)


提交成功 状态码200

#注:添加数据成功
#注:不想传 id 让它自增,那么 postman 里面把id 删掉

修改

#注:修改id为4的 数据

flask_app --> router目录 --> view01.py文件

@view01_bp.route("/modify", methods=["POST", "PUT"]) #注:修改使用PUT  改的地方
def modify():id = request.args.get("id",1, type=int) #注:没有就给1   指定整型data = request.form #注:从form表单获取它的详细信息user = Stu.query.get(id)    #注:查询跟id一样的user信息user.name = data["name"]    #注:对对象属性的操作 修改属性值user.sex = data["sex"]user.age = data["age"]user.email = data["email"]  #注:对数据库记录的属性进行修改,还没提交到数据库db.session.add(user)db.session.commit()return "modify user id ok"


删除

flask_app --> router目录 --> view01.py文件

@view01_bp.route("/delete/<int:id>", methods=["DELETE"])
#注:可以先 指定类型 int  id
def delete(id):user = Stu.query.get(id)    #注:先查询到这个id的相关数据if user:db.session.delete(user)db.session.commit()return "delete ok"

Postman下:127.0.0.1:8000/delete/3

数据删除成功

api 统一标准返回

api做统一状态返回
做标准返回,返回的数据格式要一致

步骤:创建libs目录 --> uilts.py文件
放公共里面的内容(公共函数、公共类等)
utils一般放工具的
api开发统一规范

flask_app --> libs目录 --> uilts.py文件

class UTIL:@staticmethoddef to_json(status, message, data = None):return {"status":status,           #注:状态码"message":message,           #注:提示信息"data":data             #注:数据}

flask_app --> router目录 --> view01.py文件

from libs.uilts import UTILview01_bp = Blueprint('view01',__name__,url_prefix='/')@view01_bp.route("/get/<id>", methods=["POST","GET"])
def get(id):                #注:改的地方如下#try:result_list = []if id == 'all':user_info = Stu.query.all()for user in user_info:result_list.append(user.to_json())else:user_info = Stu.query.get(int(id))result_list.append(user_info.to_json())return UTIL.to_json(status=0, message="get data is ok", data=result_list)except Exception as e:return UTIL.to_json(status=1, message=e)  #注:改的地方 UTIL.to_json()
#注:UTIL.to_json()  是定义的标准返回

Postman下


请求成功 status为0表示请求成功

[root@cPen_aliyun ~]# systemctl list-unit-files #注:查看程序是否开机自启

启动

15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ source venv/Scripts/activate                          #注:先进入虚拟环境
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ cd flask_app/
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ ls
__pycache__/  conf/        libs/      migrations/  router/    static/
app.py        data.sqlite  manage.py  model/       server.py  templates/
(venv)
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj/flask_app (master)
$ python manage.py runserver -d -h 0.0.0.0 -p 8000      #注:启动
…………* Running on http://0.0.0.0:8000/ (Press CTRL+C to quit)
(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db init
(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db migrate -m "01"
(venv) E:\web_cpen\flask_proj\flask_app>python manage.py db upgrade
python manage.py db downgrade (upgrade) 版本号

flask_marshmallow模块 序列化

flask里面 flask_marshmallow 帮你做序列化
Pycharm生成 serializer目录 存放序列化相关的东西

步骤:安装模块 flask-marshmallow

(venv) E:\web_cpen\flask_proj\flask_app>pip install flask-marshmallow

flask_app --> serializer目录 --> init.py文件、base.py文件、user.py文件

flask_app --> serializer目录 --> base.py文件

from flask_marshmallow import Marshmallow
ma = Marshmallow()  #注:生成marshmallow对象from . import user   #注:把user导入

flask_app --> serializer目录 --> init.py文件

from .base import ma         #导入它def init_app(app):ma.init_app(app)

flask_app --> app.py文件下
#注:在app.py下注册

#序列化from serializer import init_appinit_app(app)

#注:不要把 init_app()都写在一起,只会执行最后一个
#注:因为做了拆分,所以这样写

flask_app --> serializer目录 --> user.py文件

#注:输入以下数据
from .base import ma        #注:导入ma
from model.user import Stu  #注:导入需要序列化的模型class StuSchema(ma.Schema): #注:继承ma的Schema类class Meta:model = Stufileds = ("id","name","email")  #注:序列化这三个#对于单个orm对象
stu_schema = StuSchema()#对于多个orm对象
stu_schemas = StuSchema(many = True)    #注:使用对象进行序列化

flask_app --> router目录 --> view01.py文件

from serializer.user import stu_schema, stu_schemas    #注:添加这里@view01_bp.route("/get/<id>", methods=["POST","GET"])
def get(id):#try:result_list = []if id == 'all':user_info = Stu.query.all()user_list = stu_schemas.dump(user_info)    #注:添加这里# for user in user_info:#     result_list.append(user.to_json())else:user_info = Stu.query.get(int(id))user_list = stu_schema.dump(user_info)    #注:添加这里# result_list.append(user_info.to_json())return UTIL.to_json(status=0, message="get data is ok", data=user_list) #注:添加这里except Exception as e:return UTIL.to_json(status=1, message=e)

#结果:postman访问成功


#注:目前写的后端 api接口 (前后端分离)

mvc、mtv模式、前后端分离

######mvc
#web 开发设计的一种模式
#m --> model 数据
#v --> view 视图
#c --> controller 业务逻辑

#注:mvc模式

#mtv模式 python web开发设计模式
#m --> model 数据
#v --> view 视图
#t --> template 模板

#注:t不做任何逻辑处理,数据的处理都在v这里

RestFul API 表现层状态转化

######增删改查
#增加     /student/add
#修改     /student/modify
#删除     /student/delete
#查询     /student/get#如果再添加一个学校的话
#   /school/add
#   /school/delete######===> rest api
#表现层(资源)状态转移
#/student
#method   get,  post,  put,  delete

CURD
创建(Create)、更新(Update)、读取(Retrieve)和删除(Delete)

步骤:安装模块 flask-restful

(venv) E:\web_cpen\flask_proj\flask_app>pip install flask-restful

flask_app --> router目录 --> 新建 satuapi.py文件
flask_app --> router目录 --> satuapi.py文件下

#注:输入如下
from flask import Blueprint, request    #注:导入蓝图
from flask_restful import Resource, Api, reqparse
from model.user import Stu
from libs.uilts import UTIL         #注:导入统一标准返回
from serializer.user import stu_schema, stu_schemas
from model import dbstuapi_bp01 = Blueprint("stuapi",__name__, url_prefix="/api")   #注:注册蓝图#rest api绑定到蓝图上
api = Api(stuapi_bp01)class StuView(Resource):    #注:处理Stu资源的视图,继承Resource
def get(self,id):  #注:名字不能改,接收get请求 自动到这个函数   #注:这里try:if id == "all":user_info = Stu.query.all()user_list = stu_schemas.dump(user_info)# for user in user_info:#     result_list.append(user.to_json())else:user_info = Stu.query.get(int(id))user_list = stu_schema.dump(user_info)# result_list.append(user_info.to_json())return UTIL.to_json(status=0, message="get data is ok", data=user_list)except Exception as e:return UTIL.to_json(status=1, message=str(e))def post(self):                     #注:这里data = request.formuser = Stu(data["id"],data["name"],data["sex"],data["age"],data["email"])db.session.add(user)db.session.commit()return UTIL.to_json(status=0, message="add data is ok")#设置路由
api.add_resource(StuView,"/student/")
api.add_resource(StuView,"/student/<id>", endpoint = "studentapi")   #注:取一个不一样的endpoint#注:设计2种url  无论访问哪种url 都会交给StuView去处理。如果是get方法,就跳到get函数去处理,所以函数名不能变(状态转换)

flask_app --> router目录 --> init.py文件下

from .stuapi import stuapi_bp01      #注:添加这句def init_app(app):app.register_blueprint(view01_bp)app.register_blueprint(view02_bp)app.register_blueprint(stuapi_bp01)       #注:添加这句,注册蓝图

Postman访问结果
GET查询 127.0.0.1:8000/api/student/1
GET查询 127.0.0.1:8000/api/student/all


POST添加 127.0.0.1:8000/api/student/ 设置id name sex age email

自带的序列化工具

flask_app --> router目录 --> satuapi.py文件下

from flask_restful import marshal_with, fields#定义返回的格式
stu_resource_fields = {            #注:定义返回的格式"status":fields.String,"message":fields.String,"data":fields.List(fields.Nested({"name":fields.String,"age":fields.Integer,"email":fields.String}))
}class StuView(Resource):@marshal_with(stu_resource_fields)        #注:交给装饰器输出def get(self,id):  try:if id == "all":user_info = Stu.query.all()#user_list = stu_schemas.dump(user_info)# for user in user_info:#     result_list.append(user.to_json())else:user_info = Stu.query.get(int(id))#user_list = stu_schema.dump(user_info)# result_list.append(user_info.to_json())return UTIL.to_json(status=0, message="get data is ok", data=user_info)except Exception as e:return UTIL.to_json(status=1, message=str(e))

Postman下
GET 127.0.0.1:8000/api/student/all
GET 127.0.0.1:8000/api/student/1
查询成功

参数解析

flask_app --> router目录 --> satuapi.py文件下

from flask_restful import Resource, Api, reqparseclass StuView(Resource):def __init__(self):     #注:添加的地方#创建一个解析器对象self.parse = reqparse.RequestParser()   #注:指定参数解析对象#利用解析器,添加需要验证的参数self.parse.add_argument("id",help="学生id错误",type=int) #注:help错误提示self.parse.add_argument("name",help="学生name必填",required = True)self.parse.add_argument("sex",help="学生性别必填",required = True)self.parse.add_argument("age",help="学生age必填",required = True)self.parse.add_argument("email",help="学生email必填",required = True)def post(self):#data = request.formdata = self.parse.parse_args()    #注:改的地方user = Stu(data["id"], #注:从解析器里面捞取信息,而不是和以前一样从form表单获取data["name"],data["sex"],data["age"],data["email"])db.session.add(user)db.session.commit()return UTIL.to_json(status=0, message="add data is ok")#注:是解析器给我们的返回,data是解析器帮我们验证的。
#注:中间商 解析器  帮我们解析参数 是否正确,如果ok就返回,不ok就报错

Postman下
POST 127.0.0.1:8000/api/student/

CMDB

资产管理
应用管理
指令下发
监控系统
网络拓扑

https://admin.iviewui.com/home
https://wenku.baidu.com/view/584b847559eef8c75fbfb397

https://gitee.com/openspug/spug
https://gitee.com/opendevops/opendevops

地址:https://demo.opendevops.cn/login
用户:demo
密码:2ZbFYNv9WibWcR7GB6kcEY


[root@cPen_B ~]# ls     #注:中控器  B机器
cmdbclient2020-linux.zip    #注:服务器信息收集的脚本
[root@cPen_B ~]# yum install unzip
[root@cPen_B ~]# unzip cmdbclient2020-linux.zip    #注:解压脚本[root@cPen_B ~]# dmidecode           #注:看硬件相关信息
[root@cPen_B ~]# dmidecode t men       #注:看内存信息

先部署中控机

[root@cPen_B .ssh]# pip3 install paramiko           #注:安装paramiko库
[root@cPen_B ~]# cd cmdbclient2020-linux
[root@cPen_B cmdbclient2020-linux]# vim servers_info.py
def get_servers():"""从cmdb-api获取要采集哪些机器的数据数据:return:"""# 从接口获取数据server_list = {                  #注:改的地方"sn1":"192.168.0.65","sn2":"192.168.0.36"}return server_listdef copy_file(host,path):import osos.system("scp -rq -P 2233 cmdbclient2020 {host}:{path} ".format(host=host, path=path))
#注:改的地方  指定2233端口def ssh2(ip,sn,run_cmd,env_cmd):
…………ssh.connect(ip,2233,timeout=5)     #注:改的地方,指定端口
…………print('%s\tError\n'%(ip))
…………
[root@cPen_B cmdbclient2020-linux]# python3 servers_info.py
Begin......
{'sn1': {'status': True, 'message': '', …………'netmask': '255.255.255.0'}}}}}}
End......

打印捕获信息

try:
……
except Exception as e:print(str(e))

CMDB数据模型建立

15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ mkdir devopscmdb
15334@LAPTOP-5GGR0QTF MINGW64 /e/web_cpen/flask_proj
$ cp -r flask_app/* devopscmdb/     #注:复制原来的项目配置 到这个项目
#注:删掉不需要的配置
#注:项目的大体框架

一对多关系

数据模型定义
资产与厂商(一对多关系)

devopscmdb --> model文件 --> cmdb.server.py文件下

#注:输入如下全部代码
#注:定义数据模型
from .base import db        #注:导入db
from libs.enums import AssertType   #注:导入枚举类class Asset(db.Model):  #注:定义资产信息表,继承db.Model类__tablename__ = "asset"  #注:定义表名#定义资产id  唯一标识,设为主键,设置自增asset_id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)#注:定义id 自增主键#asset_type = db.Column(db.Enum("networ","server"))#定义资产类型,枚举类#1--》server  2--》networkasset_type = db.Column(db.Enum(AssertType))asset_hostname = db.Column(db.String(64)) #注:VARCHAR类型  64位asset_sn = db.Column(db.String(128), nullable=False, unique=True)#设置外键 约束                                  #注:厂商id 引入外键 ForeignKey#设置当前表manufactory字段,外键到manufactory表的manufactory_id字段#db.ForeignKey("表名.字段名")manufactory_id = db.Column(db.ForeignKey('manufactory.manufactory_id'))class Manufactory(db.Model):"""厂商表"""__tablename__= "manufactory"manufactory_id = db.Column(db.Integer, primary_key=True, autoincrement=True)manufactory_name = db.Column(db.String(64)) manufactory_tel = db.Column(db.String(11))
######反向查询字段        #注:设置反向查询字段 连接到Asset模型assets = db.relationship('Asset', backref="manufactory") #注:backref 给Asset表建立一个manufactory字段

devopscmdb --> libs文件 --> enums.py文件下

#注:输入如下全部代码
#注:libs文件 放一些自定义的东西
import enum #注:导入自带的枚举类class AssertType(enum.Enum):SERVER = 1NETWORK = 2

devopscmdb --> model文件 --> base.py文件下

from . import cmdb_server#注:__init__.py 导入时会运行
from .base import db        又会执行.base
from . import cmdb_server   就会运行。方法1.作为模块导入运行,方法2.作为主程序运行

Pycharm terminal 命令行

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db migrate -m "add cmdbserver"
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db upgrade


#注:表生成 成功

MySQL Workbench下

#注:查看创建表的语句
show create table asset;


#注:创建的manufactory表仅有3个字段,反向查询字段 在ORM层面

Pycharm --> terminal命令行

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py shell   #注:进入当前flask交互环境
>>> from model.cmdb_server import Asset, Manufactory       #注:导入2个表模型
>>> asset_sn1 = Asset(asset_sn="sn1")          #注:添加2个对象
>>> asset_sn2 = Asset(asset_sn="sn2")          #注:给对象一个序列号,其他可以不添加
>>> from model.base import db
>>> db.session.add_all([asset_sn1,asset_sn2])  #注:加入暂存区 可以这种形式 写
>>> db.session.commit()                    #注:提交
#注:表有2条记录,没有指定的字段 为空。asset_id 自增  1、2

>>> m1 = Manufactory(manufactory_name="Hp")     #注:Manufactory表插入2个数据
>>> m2 = Manufactory(manufactory_name="DELL")  #注:新建厂商 (厂商模型的对象)
>>> db.session.add(m1)
>>> db.session.add(m2)
>>> db.session.commit()                        #注:提交>>> sn3 = Asset(asset_sn="sn3")
>>> sn4 = Asset(asset_sn="sn4")
>>> db.session.add(sn3)
>>> db.session.add(sn4)
>>> db.session.commit()>>> m1 = Manufactory.query.filter_by(manufactory_name="Hp").first()    #注:获取对象记录
>>> m2 = Manufactory.query.filter_by(manufactory_name="DELL").first()
>>> sn1 = Asset.query.filter_by(asset_sn="sn1").first()
>>> sn2 = Asset.query.filter_by(asset_sn="sn2").first()
>>> sn3 = Asset.query.filter_by(asset_sn="sn3").first()
>>> sn4 = Asset.query.filter_by(asset_sn="sn4").first()
>>> m1
<Manufactory 1>
>>> sn1
<Asset 1>
>>> dir(sn1)                   #注:资产 属性,manufactory 是 厂商表 反向查询字段 给的
[……'manufactory',……]
#注:厂商表创建assets字段,关联到Asset表,并且为Asset表创建manufactory字段,关联到assets
>>> sn1.manufactory=m1            #注:使用反向查询字段,把对象赋给manufactory (资产属性 有manufactory)
#注:为sn1关联到厂商m1,指定的是sn1.manufactory_id  与下面那种效果一样
>>> sn2.manufactory_id = m2.manufactory_id
>>> db.session.add(sn1)
>>> db.session.add(sn2)
>>> db.session.commit()>>> sn3.manufactory_id = 1
>>> db.session.add(sn3)
>>> db.session.add(sn4)
>>> db.session.commit()>>> db.session.rollback()  #注:回滚
>>> m1.assets          #注:惠普厂商的资产   厂商与资产 一对多的关系
[<Asset 1>, <Asset 3>]
>>> m1.assets[0].asset_sn  #注:获取第一个资产的 sn号
'sn1'>>> sn1.manufactory
<Manufactory 1>
>>> sn1.manufactory.manufactory_name   #注:sn1.manufactory是厂商对象,通过sn1资产 访问 厂商名
'Hp'
>>> dir(m1)            #注:m1有assets 属性 (反向查询字段),数据库不显示,属于ORM层
[……'assets'……]
#注:厂商和资产  一对多的关系#注:外键非常消耗性能。表创建好之后  可以把数据库里的外键删掉,不会影响 flask层面

devopscmdb --> model文件 --> cmdb.server.py文件下

#注:class Manufactory(db.Model): 添加如下 进行完善和补充
class Manufactory(db.Model):……
# 后期做优化note = db.Column(db.Text)create_at = db.Column(db.DateTime())update_at = db.Column(db.DateTime())# 是否启用当前数据status = db.Column(db.Integer())  #注:不需要删除数据 设置status就可以

资产与IDC
devopscmdb --> model文件 --> cmdb.server.py文件下

class Asset(db.Model):idc_id = db.Column(db.ForeignKey('idc.idc_id'))class IDC(db.Model):__tablename__ = "idc"idc_id = db.Column(db.Integer, primary_key=True, autoincrement=True)# 反向查询: backref='idc'  => Asset.idcassets = db.relationship('Asset', backref='idc')idc_name = db.Column(db.String(64))idc_name_cn = db.Column(db.String(64))idc_region = db.Column(db.String(64))# 运营商idc_isp = db.Column(db.String(64))note = db.Column(db.Text)create_at = db.Column(db.DateTime())update_at = db.Column(db.DateTime())status = db.Column(db.Integer())

Terminal命令行下

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db migrate -m "add idc"
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db upgrade

#注:数据库里的外键删掉,在Python里建立这种外键关系

多对多关系

业务线与用户 (M2M关系)

业务线  理解成应用
业务线与负责人的关系:
一个人负责多个业务线,一个业务线有多个负责人 (多对多的关系)

#解决方法:引入中间表,存它们的映射关系
员工表 、应用表 和 中间表。最终通过id联系在一起
#注:中间表 存放映射关系信息
#注:中间表只存放id,通过id去寻找

devopscmdb --> model文件 --> cmdb.server.py文件下
#注:存放于cmdb有关的数据模型

#注:复制粘贴from .user import UserProfile          #注:导入
#注:中间表,可以这么写
business_unit_users = db.Table("business_unit_users",# 用户iddb.Column("user_profile_id", db.ForeignKey("user_profile.user_profile_id")),# 业务线iddb.Column("business_unit_id", db.ForeignKey("business_unit.business_unit_id")))class BusinessUnit(db.Model):__tablename__ = "business_unit"business_unit_id = db.Column(db.Integer, primary_key=True, autoincrement=True)business_unit_name = db.Column(db.String(64))business_unit_name_cn = db.Column(db.String(64))# m2m =>好多人 => 管理员# # 一个业务应该由很多人来维护, 一个人可以维护多个业务线managers = db.relationship("UserProfile",# 指定中间表
#注:中间表从business_unit_users去捞取,为创建字段business_unitssecondary=business_unit_users,backref="business_units")note = db.Column(db.Text)create_at = db.Column(db.DateTime())update_at = db.Column(db.DateTime())status = db.Column(db.Integer())

devopscmdb --> model文件 --> user.py文件下
#注:存放于user有关的数据模型

#注:复制粘贴class UserProfile(db.Model):__tablename__ = "user_profile"user_profile_id = db.Column(db.Integer, primary_key=True, autoincrement=True)user_profile_name = db.Column(db.String(32), nullable=False)user_profile_email = db.Column(db.String(32), nullable=False, unique=True)user_profile_mobile =  db.Column(db.String(11))note = db.Column(db.Text)create_at = db.Column(db.DateTime())update_at = db.Column(db.DateTime())status = db.Column(db.Integer())

Pycharm terminal 命令行下

#注:生效表
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db migrate -m "add idc"
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db upgrade     #注:生效

Pycharm terminal 命令行下

>>> from model.cmdb_server import BusinessUnit
>>> from model.user import UserProfile
>>> user1 = UserProfile(user_profile_name="tlf",user_profile_email="123@abc1.com") #注:创建3个数据
>>> user2 = UserProfile(user_profile_name="pyf",user_profile_email="123@abc2.com")
>>> user3 = UserProfile(user_profile_name="xy",user_profile_email="123@abc3.com")
>>> from model.base import db
>>> db.session.add_all([user1,user2,user3])
>>> db.session.commit()                                                #注:提交
#注:设置它的业务线
>>> b1 = BusinessUnit(business_unit_name = "cq")
>>> b2 = BusinessUnit(business_unit_name = "mhxy")
>>> b3 = BusinessUnit(business_unit_name = "csgo")
#注:对他进行生效
>>> db.session.add_all([b1,b2,b3])
>>> db.session.commit()
>>> dir(b2)            #注:b2的managers 属性,知道业务线  由谁管
[……'managers'……]
>>> b2.managers        #注:b2目前没有负责人
[]
>>> b2.business_unit_name      #注:b2现在没有负责人,b2是梦幻西游的业务线
'mhxy'

为中间表创建映射关系

#注:这里 和我写的不一样,我的user_profile_id 是 1、2、3 右键 submit提交

#注:b2是梦幻西游业务线,b2.managers 管理梦幻西游的

Pycharm terminal 命令行下

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py shell
>>> from model.cmdb_server import BusinessUnit
>>> b1 = BusinessUnit.query.filter_by(business_unit_name="cq").first() #注:查询 传奇的业务线
>>> b1
<BusinessUnit 1>
>>> dir(b1)
[……'managers'……]          #注:managers是我建立的映射关系
>>> b1.managers                #注:当前业务线 的负责人  2个
[<UserProfile 3>, <UserProfile 4>]
>>> from model.user import UserProfile         #注:导入 UserProfile
>>> user1 = UserProfile.query.filter_by(user_profile_name=”tlf”).first()
>>> dir(user1)
[……'business_units'……]
#注:有business_units的记录,因为 为userProfile这个类增加了 business_units  用于反向查询的字段
>>> user1.business_units                   #注:user1 负责的业务
[<BusinessUnit 1>, <BusinessUnit 2>]
#注:这就是  多对多的关系
>>> user1.business_units[0].business_unit_name #注:捞取负责的业务的信息   因为user1.business_units返回的是列表
>>> ‘cq’
>>> user1.business_units[1].business_unit_name
>>> ‘mhxy’

2个外键 同时关联到一个表

devopscmdb --> model文件 --> cmdb.server.py文件下
#注:保存 硬件负责人的表结构 和应用负责人的表结构一致,可以把这张表放在一起

#注:添加如下代码
class Asset(db.Model):      #注:做区分,2个外键关联到 同一张表……# 业务线,属于什么应用,应用组business_id = db.Column(db.ForeignKey("business_unit.business_unit_id"))#硬件负责人admin_id = db.Column(db.ForeignKey("business_unit.business_unit_id"))# 由于这里两个字段链接到同一个表了,不避免区分不开,relationship写在这里# 为BusinessUnit表添加了两个字段: asset_businesses, asset_adminsbusiness_unit = db.relationship("BusinessUnit", backref="asset_businesses",foreign_keys=[business_id])admin = db.relationship("BusinessUnit", backref="asset_admins",foreign_keys=[admin_id])
#注:将 2种关系 外键关联id 写在Asset这里,为它每一个关联的外键创建一个BusinessUnit的反向查询字段class BusinessUnit(db.Model):……# assets = db.relationship("Asset",backref="business_units") #注:不要写这个关联 因为有2个字段
#注:这样解决 2个字段 关联同一张表

Pycharm terminal 命令行

#注:生效到数据库
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db migrate -m "modify asset"
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db upgrade(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py shell
>>> from model.cmdb_server import Asset, BusinessUnit
>>> sn1 = Asset.query.filter_by(asset_sn="sn1").first()
#注:通过sn1的business_unit属性访问sn1的业务线组
#注:通过sn1的admin属性访问sn1的硬件组

一对一关系

服务器与资产表(一对一关系)

devopscmdb --> model文件 --> cmdb.server.py文件下

# Server与Asset关系
class Asset(db.Model):# 一对一关系 server与assetserver = db.relationship("Server", backref="asset", uselist=False)class Server(db.Model):__tablename__ = "server"server_id = db.Column(db.Integer, primary_key=True, autoincrement=True)asset_id = db.Column(db.Integer, db.ForeignKey('asset.asset_id'))server_cpu_count = db.Column(db.Integer)server_cpu_cour_count = db.Column(db.Integer)server_cpu_model = db.Column(db.String(64))server_raid_type = db.Column(db.String(6))server_ram_size = db.Column(db.Integer)note = db.Column(db.Text)create_at = db.Column(db.DateTime())update_at = db.Column(db.DateTime())status = db.Column(db.Integer())

Pycharm terminal 命令行

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py shell>>> from model.cmdb_server import Asset, Server
>>> from model.base import db
>>> sn1 = Asset.query.filter_by(asset_sn="sn1").first()
>>> sn2 = Asset.query.filter_by(asset_sn="sn2").first()
>>> sn1
<Asset 1>
>>> server1 = Server.query.filter_by(asset_id=1).first()
>>> dir(server1)
[…… 'asset', ……]
>>> server1.asset
<Asset 1>
>>> server1.asset.asset_sn
'sn1'
>>> server2 = Server(asset_id=1)
#注:不是严格的一对一,干扰不到数据库的行为,只是ORM层面的
>>> db.session.add(server2)
>>> db.session.commit()>>> server3 = Server(server_cpu_model="intel")
>>> db.session.add(server3)
>>> db.session.commit()
>>> server3.asset = sn1           #注:仅仅只是对 设置的这个属性 有效果 (一对一)
……  util.warn(              #注:报错

复制粘贴 创建其他的表

…………
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db migrate -m "add server"
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db upgrade


#注:数据库 就已经弄好了
#注:准备写接口了

获取服务器数据接口

devopscmdb --> router目录 --> server.py文件

#注:输入以下所有代码
from flask import Blueprint     #注:导入蓝图
from flask_restful import Api, Resource #注:满足 restful 格式
from model.cmdb_server import Server
from model.base import dbserver_bp = Blueprint("server",__name__, url_prefix="/api/cmdb") #注:创建蓝图#api 蓝图注册
api = Api(server_bp)#server视图
class ServerView(Resource):  #注:编写接口def get(self):server_info = Server.query.all()    #注:获取所有服务器信息tmp_list = []     #注:存放数据 json格式 列表里面包字典for server in server_info: #注:序列化的 东西  可以自己写 tmp_dict = {}tmp_dict["server id"] = server.server_id  #注:本身的属性tmp_dict["sn"] = server.asset.asset_sn  #注:添加返回的数据tmp_dict["os"] = server.os.os_type      #注:这2个数据 是通过relationship外键 获取tmp_list.append(tmp_dict)return tmp_listapi.add_resource(ServerView, "/servers")

devopscmdb --> router目录 --> init.py文件

#注:输入以下所有代码
from .server import server_bpdef init_app(app):app.register_blueprint(server_bp)   #注册server_bp

devopscmdb --> app.py文件

#注:解除注释
def create_app(config=None):
……# 注册蓝图from router import init_appinit_app(app)
……

Pycharm terminal 命令行

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py runserver -d -h 0.0.0.0 -p 8000
postman下
GET      127.0.0.1:8000/api/cmdb/servers/
#注:获取数据成功,如下
-----------------------------------------------
[{"server id": 1,"sn": "sn1","os": "linux"}
]
-----------------------------------------------

devopscmdb --> libs目录 --> response.py文件
#注:步骤 做标准化返回

#注:lib下面一般放 公共的类、库、其他处理的东西
#注:这步 是 做标准化返回
#注:data  形参 最好不要定义成可变数据类型 ,如 [ ] 列表#统一标准化返回
def generate_reponse(data = None, message = "ok", status_code=10000)
if data is None:data = []return {"status_code":status_code,"message":message,"data":data}#注:主函数  处理的地方  尽量简洁,具体的操作  尽量放在其他地方

devopscmdb --> libs目录 --> parse.py文件

#注:复制粘贴  解析 步骤
#注:做了一些兼容
from enum import Enumdef get_value(obj, key):if obj:                #注:如果有objvalue = getattr(obj, key)      #注:Python的自省return value.name if isinstance(value, Enum) else value  #注:是否是枚举类
#注:是枚举类 就返回 name  否则返回valueelse:return ""def get_value_list(objlist, *keys):"""返回一个列表数据"""if len(keys) == 0:return list()else:result = list()for item in objlist:if len(keys) == 1:result.append(getattr(item, keys[0]))else:t_result = dict()for key in keys:t_result[key] = getattr(item, key)result.append(t_result)return resultdef get_ip(nics, eth):    #注:获取  公/私网 ipfor nic in nics:if eth == nic.nic_name:return nic.nic_ipaddrreturn ""
#注:私网ip eth0
#注:公网ip eth1def server_item_parse(server):# print(server)result = {"id": server.server_id,"os": get_value(server.os, "os_version"),   #注:参数1 对象,参数2 属性"hostname": get_value(server.asset, "asset_hostname"),"sn": get_value(server.asset, "asset_sn"),"asset_type": get_value(server.asset, "asset_asset_type"),"ip":  get_ip(server.nics, "eth0"),"public_ip": get_ip(server.nics, "eth1"),"private_ip": get_ip(server.nics, "eth0"),"port": 22,"idc": get_value(server.asset.idc, "idc_name_cn"),"admin_user": get_value_list(server.asset.admin.managers, "user_profile_name") if server.asset.admin else [],"region": get_value(server.asset.idc, "idc_region"),"state": "true","detail": get_value(server, "note"),"create_time": get_value(server, "create_at"),"update_time": get_value(server, "update_at"),}return resultdef servers_parse(server):if isinstance(server, list):      #注:如果server是一个列表# [<server obj>, <server obj>]result = [server_item_parse(item) for item in server]     #注:就循环else:# server = <server obj>result = server_item_parse(server)return result

devopscmdb --> router目录 --> server.py文件

#注:添加如下代码
from flask import Blueprint
from flask_restful import Api, Resource
from model.cmdb_server import Server
from model.base import db
from libs.parse import servers_parse        #注:导入 解析
from libs.response import generate_response #注:导入 标准化返回server_bp = Blueprint("server",__name__, url_prefix="/api/cmdb")#api 蓝图注册
api = Api(server_bp)#标准化返回: 自己定义
#数据序列化: 自己定义
#定义异常标准化#server视图
class ServerView(Resource):def get(self):server_info = Server.query.all()return generate_response(servers_parse(server_info))api.add_resource(ServerView, "/servers/")

Pycharm terminal 命令行

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py runserver -d -h 0.0.0.0 -p 8000

Postman下

GET      127.0.0.1:8000/api/cmdb/servers/        #注:返回成功
{"status_code": 10000,"message": "ok","data": [{"id": 1,
…………"update_time": null}]
}

GET      127.0.0.1:8000/api/cmdb/servers/


#注:http 出错的话,直接返回一个错误界面,对于接口是不友好的。不是返回错误页面,而是统一标准化 返回。客户端访问 不希望返回页面

from werkzeug.exceptions import HTTPException
HTTPException ctrl+右键  进入 HTTPException类,修改get_body方法

devopscmdb --> libs目录 --> error_code.py文件

#注:libs下一般放 公共的类、库、其他处理的东西、对数据的获取
#注:重写HTTPException ,重写get_body、get_headers方法
from werkzeug.exceptions import HTTPException
class APIException(HTTPException):      #注:定义APIExceptioncode = 500             #注:http的codemessage = "opps!"status_code = 99999         #注:应用程序的codedef __init__(self, message = None,code = None,status_code = None,headers = None):super().__init__()if code:              #注:如果code存在self.code = codeif status_code:self.status_code = status_codeif message:self.message = messagedef get_body(self, environ=None):body = dict(message = self.message,status_code = self.status_code)import jsoncontent = json.dumps(body)return contentdef get_headers(self, environ=None):return {('content_type','application/json')}

devopscmdb --> libs目录 --> handler.py文件

#注:定义处理异常的模块
from flask_restful import HTTPException
from libs.error_code import APIExceptiondef default_error_hander(ex):       #注:接收一个异常if isinstance(ex, APIException):    #注:如果它是APIException异常return exif isinstance(ex, HTTPException):  #注:如果它是HTTPException异常code = ex.codemessage = ex.descriptionstatus_code = 10001return APIException(code = code,message=message, status_code = status_code)return APIException()        #注:如果它是其他异常,继承 默认的 APIException

devopscmdb --> router目录 --> server.py文件

from libs.handler import default_error_handler#指定api接口异常处理函数
#开发环境还是不添加的号
api.handle_error = default_error_handler       #注:指定 重写的 自定义异常


postman下

GET  127.0.0.1:8000/api/cmdb/servers/
#注:捕获到错误异常
{"message": "opps!","status_code": 99999
}
#注:序列化异常也可以捕获

嵌套蓝图

#注:蓝图用来注册路由#/v1/api/cmdb/servers/
#/v1/api/cmdb/memory
#/v1/api/user/#------> /v2######
#1、/v1/api
#2、/cmdb/server  /cmdb/memory  /user#蓝图嵌套
#blueprint 不自带嵌套功能

#注:新建 v1目录
devopscmdb --> router目录 --> v1目录 --> server.py文件

devopscmdb --> libs目录 --> netstable_blueprint.py文件

#注:复制粘贴  网上公认的模板  。做了一个拼接
from flask import Blueprintclass NestableBlueprint(Blueprint):def register_blueprint(self, blueprint, **options):def deferred(state):# state.url_prefix => 自己url前缀 + blueprint.url_prefix => /v3/api/cmdb/url_prefix = (state.url_prefix or u"") + (options.get('url_prefix', blueprint.url_prefix) or u"")if 'url_prefix' in options:del options['url_prefix']# app.register_blueprint(blueprint, '/v3/api/cmdb/')state.app.register_blueprint(blueprint, url_prefix=url_prefix, **options)self.record(deferred)

devopscmdb --> router目录 --> v1目录 --> server.py文件

#注:修改如下
server_bp = Blueprint("server",__name__, url_prefix="/cmdb")  #注:前缀 改为/cmdb

devopscmdb --> router目录 --> v1目录 --> init.py文件

#注册二级蓝图
from libs.netstable_blueprint import NestableBlueprint
from .server import server_bpv1_bp = NestableBlueprint("v1",__name__, url_prefix="/v1/api/")  #注:
v1_bp.register_blueprint(server_bp)

devopscmdb --> router目录 --> init.py文件

from router.v1 import v1_bpdef init_app(app):    app.register_blueprint(v1_bp)   #注:注册v1_bp蓝图

postman下

#注:获取成功
GET 127.0.0.1:8000/v1/api/cmdb/servers/{"status_code": 10000,"message": "ok","data": [{"id": 1,
…………"update_time": null}]
}

调用接口获取服务器数据

把ip地址 从服务器上去获取
#注:在win pycharm上面开启 8000端口,能够通过API 访问 数据库。 Server端 B主机(linux) requests 访问 client端8000端口,获取A机器的ip地址,scp跑在A机器上 获取A机器的信息

(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py runserver -d -h 0.0.0.0 -p 8000

#注:通过接口 获取ip信息。在脚本里导入 requests模块
#注:从接口获取数据,客户端 在中控机 linux,服务器是Windows 。访问Windows的接口ip网站,获取它的ip地址信息

pycham 编辑远程脚本

参考博文 https://www.cnblogs.com/xiao-apple36/p/8587086.html
菜单栏Tools --> Deployment --> Configuration…


#注:Automatic Upload (always) #注:自动上传
#注:Browse Remote Host #注:浏览远程主机

数据库里 存放ip的字段 数据设置
#注:主机A的ip

#注:需要添加 nic_name 为”eth0” ,因为是靠它 寻找的

cmdbclient2020-linux --> settings.py文件

#注:修改url
API = "http://192.168.0.61:8000/v1/api/cmdb/servers/"#注:修改为 192.168.0.61

#注:查看Windows的ip地址

#注:在linux机器(客户端)上 检测 网络连通性
[root@cPen_B cmdbclient2020-linux]# ping 192.168.0.61          #注:ping通
[root@cPen_B cmdbclient2020-linux]# telnet 192.168.0.61 8000       #注:telnet 8000 通

cmdbclient2020-linux --> servers_info.py文件

import requestsdef get_servers():"""从cmdb-api获取要采集哪些机器的数据数据:return:"""# 从接口获取数据from settings import APIcontent = requests.get(API).textdatas = json.loads(content)["data"]  #注:从字符串转换成json对象server_list = {}for data in datas:  #注:循环获取 里面的内容server_list[data["sn"]] = data["ip"]# server_list = {#     "sn1":"192.168.0.65",#     "sn2":"192.168.0.36"# }return server_listdef copy_file(host,path):     #注:修改端口 2233import osos.system("scp -rq -P 2233 cmdbclient2020 {host}:{path}".format(host=host, path=path))def ssh2(ip,sn,run_cmd,env_cmd):  #注:修改端口 2233try: ……ssh.connect(ip,2233,timeout=5)#注:服务监听 要监听到 本机所有ip上面 0.0.0.0 ;监听到 127.0.0.1 外面访问不了

Linux下

[root@cPen_B cmdbclient2020-linux]# python3 servers_info.py
Begin......                         #注:获取成功
{'sn1': {'status': True, 'message': '', …… 'netmask': '255.255.255.0'}}}}}}
End......
[root@cPen_B cmdbclient2020-linux]#

优化:增加API授权

#注:使用APIToken 保存授权密钥 授权的key值

#注:模型放在devopscmdb --> model目录 --> user.py文件下

devopscmdb --> model目录 --> user.py文件下

#注:输入以下全部代码
from libs.enums import MethodTypeclass UserProfile(db.Model):……api_token_permissions = db.Table("api_token_permissions",     #注:中间表db.Column("api_token_id",db.ForeignKey("api_token.api_token_id")),db.Column("api_permission_id",db.ForeignKey("api_permission.api_permission_id")))class APIToken(db.Model):__tablename__ = "api_token"api_token_id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)api_token_appid = db.Column(db.String(64))api_token_secretkey = db.Column(db.String(64))user_profile_id = db.Column(db.ForeignKey('user_profile.user_profile_id')) #注:加入外键permissions = db.relationship("APIPermission",secondary = api_token_permissions,backref = "api_tokens")note = db.Column(db.Text)          #注:加入 公共字段create_at = db.Column(db.DateTime())update_at = db.Column(db.DateTime())status = db.Column(db.Integer())class APIPermission(db.Model):      #注:更细的权限,允许 哪些接口、方法 访问__tablename__ = "api_permission"api_permission_id = db.Column(db.INTEGER, primary_key=True, autoincrement=True)api_permission_url = db.Column(db.String(256))api_permission_method_type = db.Column(db.Enum(MethodType))    #注:枚举型note = db.Column(db.Text)         #注:加入 公共字段create_at = db.Column(db.DateTime())update_at = db.Column(db.DateTime())status = db.Column(db.Integer())#注:程序 肯定有很多的url,一个url可以给很多接口去使用,一个接口可以有很多个url,多对多的关系

pycharm terminal命令行

#注:创建表
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db migrate -m "add api token"
(venv) E:\web_cpen\flask_proj\devopscmdb>python manage.py db upgrade

pycharm MySQL 插入数据


#注:中间表

devopscmdb --> libs目录 --> authorize.py文件下

#注:创建新的认证模块
from flask import request
from model.user import APIToken
from .error_code import APIAuthorizedException  #注:用户认证失败的自定义异常
from hashlib import md5         #注:导入md5def api_authorize():             #注:复制粘贴以下全部代码params = request.argsappid = params.get('appid')salt = params.get('salt')sign = params.get('sign')api_token = APIToken.query.filter_by(api_token_appid=appid).first()if not api_token:          #注:第1步 appid的认证raise APIAuthorizedException(message="认证失败!没有查找到api_token")has_permission(api_token, url=request.path, method=request.method)user_appid = api_token.api_token_appiduser_secretkey = api_token.api_token_secretkeyuser_sign = user_appid + salt + user_secretkeym1 = md5()m1.update(user_sign.encode(encoding='utf8'))user_sign = m1.hexdigest()if sign != user_sign:raise APIAuthorizedException()else:return Truedef has_permission(api_token, url, method):  #注:复制粘贴以下全部代码"""权限该api是否有指定url和指定方法的权限"""# 从服务端查找appid及对应的秘钥mypermission = method + urlall_permissions = [permission.api_permission_method_type.name + permission.api_permission_url for permission inapi_token.permissions]if mypermission not in all_permissions:raise APIAuthorizedException(message="没有当前接口的权限")return True

devopscmdb --> libs目录 --> error_code.py文件下

#注:认证失败的返回信息
class APIAuthorizedException(APIException): #注:用户认证失败的自定义异常,继承APIExceptionmessage = "用户认证失败"status_code = 10004           #注:给应用的返回码code = 401                #注:给http的返回码

devopscmdb --> v1目录 --> server.py文件下

#注:加入认证
from libs.authorize import api_authorizeclass ServerView(Resource):def get(self):api_authorize()……

postman下
GET 127.0.0.1:8000/v1/api/cmdb/servers/

cmdbclient2020-linux --> settings.py文件下

#注:修改如下代码
API = "http://192.168.0.61:8000/v1/api/cmdb/servers/"
APPID = 'cmdbclient'
SECRETKEY = '123456'
VERSION = "v1"
KEY = '299095cc-1330-11e5-b06a-a45e60bec08b'

cmdbclient2020-linux --> servers_info.py文件下

#注:添加如下代码
from hashlib import md5def get_servers():"""从cmdb-api获取要采集哪些机器的数据数据:return:"""# 从接口获取数据from settings import API, APPID, SECRETKEYsalt = random.randint(32768, 65536)sign = APPID + str(salt) + SECRETKEYm1 = md5()m1.update(sign.encode(encoding='utf8'))sign = m1.hexdigest()params = {            #注:认证通过 传递这3个参数,认证不通过 不传递这3个参数"appid": APPID,"salt": salt,"sign": sign,}content = requests.get(API,params=params).textdatas = json.loads(content)["data"]  #注:从字符串转换成json对象server_list = {}for data in datas:  #注:循环获取server_list[data["sn"]] = data["ip"]# server_list = {#     "sn1":"192.168.0.65",#     "sn2":"192.168.0.36"# }return server_list#注:服务端 颁布密钥 给客户端 去使用

linux下

#注:打印出来了
[root@cPen_B cmdbclient2020-linux]# python3 servers_info.py
Begin......
{'sn1': {'status': True, 'message': ……'netmask': '255.255.255.0'}}}}}}
End......

Postman下

#注:获取成功
127.0.0.1:8000/v1/api/cmdb/servers/?appid=cmdbclient&salt=42291&sign=ab3953c19b0516b2c38f5d79d07f05e7

29_python笔记-flask框架相关推荐

  1. Python笔记-Flask框架Get和Post参数相关

    程序结构如下: 源码如下: application.py from flask import Flask from controller import index_pageapp = Flask(__ ...

  2. flask 框架第一天学习笔记

    Flask Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架. Flask 本身相当于一个内核,其他几乎 ...

  3. python Flask框架如何请求及返回数据——flask详细教程

    python Flask框架如何请求及返回数据--flask详细教程 文章目录: 1 Flask介绍 1.1 Flask简单介绍 1.2 Flask相关资料信息 2 Flask快速入门 2.1 Fla ...

  4. 谈谈Python的Flask框架学习与福利分享

    在秋天中暑 熬过了炎炎夏日,却在这个初秋的日子中暑了.本来休息不好,今天又跑了一天,结果回来坐车吹空调冷热交替的崩溃了... 脑壳疼 回家就躺倒睡了一觉,感觉舒服点了,起床开电脑却又不知道学点什么,想 ...

  5. python学习之Flask框架(一)

    前言:本人广西医科大学公共事业管理专业大二学生,大一开始自学python,大一期末报名了python课程学习,目前学习到flask框架(因为高中文科生和英语不太行的缘故,学习进度较慢),前面的笔记都是 ...

  6. linux使用flask设计网站,linux下Flask框架搭建简单网页

    开始安装FLASK需要创建一个虚拟环境,虚拟环境可以不干扰正在使用的系统环境,避免影响,并且也不需要完全的root权限,更加安全可靠. 搭建环境 Python3.4 进入到microblog目录下创建 ...

  7. Flask框架基础Jinja2模板

    Flask框架基础Jinja2模板-- 潘登同学的flask学习笔记 文章目录 Flask框架基础Jinja2模板-- 潘登同学的flask学习笔记 return 模板 Template 模板的使用 ...

  8. flask html 模板继承,Flask框架模板继承实现方法分析

    Flask框架模板继承实现方法分析 本文实例讲述了Flask框架模板继承实现方法.分享给大家供大家参考,具体如下: 在模板中,可能会遇到以下情况: 多个模板具有完全相同的顶部和底部内容 多个模板中具有 ...

  9. Flask框架-Graphql的使用

    Flask框架-Graphql的使用 – 潘登同学的flask学习笔记 文章目录 Flask框架-Graphql的使用 -- 潘登同学的flask学习笔记 Graphql GraphQL与RESTfu ...

最新文章

  1. kugoo应用心得——p2p下载,共享文件
  2. 如何给屏幕设置一个充满全屏的图片
  3. 003_Spring Data JPA分页和排序查询
  4. 喜报 | 大地影院集团签约神策数据,影院 + 数据化高光时刻开启
  5. [C#.NET 拾遗补漏]06:单例模式最佳实践
  6. python3列表生成式中的for循环与普通放在外面的for循环细微差异
  7. 二、Java面向对象(7)_封装思想——访问修饰符
  8. 《Algorithms》Comparable 实现快速排序三向切分的快速排序
  9. 顺丰业绩突然爆雷:预计巨亏9-11亿!京东、美团等10家平台承诺不用大数据杀熟;苹果推迟MacBook和iPad生产|极客头条...
  10. 网状meta分析怎么入门?网状meta分析与meta分析区别
  11. 信息系统项目管理师---第四章项目整体管理历年考试题
  12. 手机中的劳力士:HTC是执迷不悟还是不悔?
  13. 初探巨杉分布式数据库
  14. php.c drcom,成功 将校园客户端drcom搞进openwrt
  15. 解决-画图程序无法读取-无效的位图文件
  16. Axon Framework架构概述
  17. 群晖 NAS 与 百度云网盘互相进行同步
  18. dsa数字签名c语言编程,DSA 数字签名算法
  19. 字间距、词间距的使用-CSS入门基础(010)
  20. 《Kotlin从小白到大牛》第28章:项目实战1:开发PetStore宠物商店项目

热门文章

  1. 顽强拼搏展现自我合作共赢激情超越——记湖南工程职院美和易思篮球友谊赛
  2. 局部对比度结合区域显著性红外弱小目标检测
  3. Echarts+大屏
  4. 汇丰软件测试英语面试,汇丰笔试 - Beyond my life. - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
  5. hiai和鸿蒙的关系,HiAI
  6. 《科尼龙作曲家》——音乐课教学的绝佳工具
  7. 零基础《7天学会PPT》系列教程(WPS版)—— 第1天 一页一故事
  8. 旺季翻盘看这里!揭秘2020亚马逊黑五网一营销爆火新玩法!
  9. 安卓应用全屏适配(游戏)
  10. [转]麻辣隔壁的考研英语的真相!!!!!!!!!!!