create database flask_app;
linux mysql 下 设置其他主机可以连接
UPDATE mysql.user SET Host='%' WHERE Host='localhost' AND User='root';
FLUSH PRIVILEGES;
·创建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 "[email protected]"
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)
flask 基于werkzeug工具箱和jinja2模板引擎开发的一个轻量级web框架
#创建第一个flask项目
from flask import Flask
app = 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/", view_func=index2) #注:传入参数
#app.add_url_rule("/index/", 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没有指定,默认就是函数名
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 Flask
print(os.environ)
def create_app(config=None):
app = Flask(__name__)
# load default configuration
app.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 configuration
if 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_app
app = 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 Flask
def create_app(config=None):
app = Flask(__name__)
# load default configuration
app.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 configuration
if 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 Blueprint
view01_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 Blueprint
view02_bp = Blueprint('view02',__name__,url_prefix='/view02/')
@view02_bp.route("/", methods=["POST","GET"])
def index():
return "this is view02 blueprint"
router目录 --> init.py文件
from .view01 import view01_bp
from .view02 import view02_bp
def init_app(app):
app.register_blueprint(view01_bp)
app.register_blueprint(view02_bp)
server.py文件
#不建议这样写
from app import create_app
from router import init_app
app = create_app()
init_app(app)
app.run(host=app.config["HOST"],
port=app.config["PORT"],
debug=app.config["DEBUG"])
app.py文件
import os
from flask import Flask
def create_app(config=None):
app = Flask(__name__)
# load default configuration
app.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 configuration
if 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_app
init_app(app)
return app
主文件 server.py
from app import create_app
app = 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,验证返回结果
前后端分离 好处:页面分开,各自写各自的页面,统一调用接口就可以了
前后端隔离 好处:可以并行开发,增加开发效率,增加人力资源的利用
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_template
view02_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文件
#注:渲染成功
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,即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 db
class 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 db
def 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 db
class 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 = id
self.name = name
self.sex = sex
self.age = age
def 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 Stu
view01_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 #注:得到的结果就是数据库里的东西
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 db
def 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
点 + 号插入数据
flask_app --> model目录 --> user.py文件
from sqlalchemy import Column, String #注:加这句话 第二种模型的定义
from .base import db
class 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 Stu
view01_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 db
class 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 = email
def to_json(self):
return {
…………
"email":self.email
}
创建文件:跟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 db
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))
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) 版本号
#步骤:点击左上角 +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 #注:查看表数据
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()生成类似列表一样的东西,列表里面的 和 ,每一个对象 就是 每一行数据 (刚才新增的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 Stu
view01_bp = Blueprint('view01',__name__,url_prefix='/') #注:‘/’改的地方
@view01_bp.route("/get", methods=["POST","GET"])
def get(): #注:改的地方,逻辑
id = request.args.get("id","all") #注:这样获取 传递进来的id
result_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 Stu
view01_bp = Blueprint('view01',__name__,url_prefix='/')
@view01_bp.route("/get/" , 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)
@view01_bp.route("/add", methods=["POST", "GET"])
def add():
data = request.form
user = 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/" , 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做统一状态返回
做标准返回,返回的数据格式要一致
步骤:创建libs目录 --> uilts.py文件
放公共里面的内容(公共函数、公共类等)
utils一般放工具的
api开发统一规范
flask_app --> libs目录 --> uilts.py文件
class UTIL:
@staticmethod
def to_json(status, message, data = None):
return {"status":status, #注:状态码
"message":message, #注:提示信息
"data":data #注:数据
}
flask_app --> router目录 --> view01.py文件
from libs.uilts import UTIL
view01_bp = Blueprint('view01',__name__,url_prefix='/')
@view01_bp.route("/get/" , 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() 是定义的标准返回
[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里面 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_app
init_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 = Stu
fileds = ("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/" , 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
#web 开发设计的一种模式
#m --> model 数据
#v --> view 视图
#c --> controller 业务逻辑
#注:mvc模式
#mtv模式 python web开发设计模式
#m --> model 数据
#v --> view 视图
#t --> template 模板
#注:t不做任何逻辑处理,数据的处理都在v这里
######增删改查
#增加 /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 db
stuapi_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.form
user = 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/" , 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, reqparse
class 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.form
data = 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/
资产管理
应用管理
指令下发
监控系统
网络拓扑
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_list
def copy_file(host,path):
import os
os.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))
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--》network
asset_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 = 1
NETWORK = 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
#注:查看创建表的语句
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.idc
assets = 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",
# 用户id
db.Column("user_profile_id", db.ForeignKey("user_profile.user_profile_id")),
# 业务线id
db.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_units
secondary=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="[email protected]") #注:创建3个数据
>>> user2 = UserProfile(user_profile_name="pyf",user_profile_email="[email protected]")
>>> user3 = UserProfile(user_profile_name="xy",user_profile_email="[email protected]")
>>> 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_admins
business_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与asset
server = 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 db
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() #注:获取所有服务器信息
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_list
api.add_resource(ServerView, "/servers")
devopscmdb --> router目录 --> init.py文件
#注:输入以下所有代码
from .server import server_bp
def init_app(app):
app.register_blueprint(server_bp) #注册server_bp
devopscmdb --> app.py文件
#注:解除注释
def create_app(config=None):
……
# 注册蓝图
from router import init_app
init_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 Enum
def get_value(obj, key):
if obj: #注:如果有obj
value = getattr(obj, key) #注:Python的自省
return value.name if isinstance(value, Enum) else value #注:是否是枚举类
#注:是枚举类 就返回 name 否则返回value
else:
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 result
def get_ip(nics, eth): #注:获取 公/私网 ip
for nic in nics:
if eth == nic.nic_name:
return nic.nic_ipaddr
return ""
#注:私网ip eth0
#注:公网ip eth1
def 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 result
def servers_parse(server):
if isinstance(server, list): #注:如果server是一个列表
# [, ]
result = [server_item_parse(item) for item in server] #注:就循环
else:
# server =
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): #注:定义APIException
code = 500 #注:http的code
message = "opps!"
status_code = 99999 #注:应用程序的code
def __init__(self, message = None,
code = None,
status_code = None,
headers = None):
super().__init__()
if code: #注:如果code存在
self.code = code
if status_code:
self.status_code = status_code
if message:
self.message = message
def get_body(self, environ=None):
body = dict(
message = self.message,
status_code = self.status_code
)
import json
content = json.dumps(body)
return content
def get_headers(self, environ=None):
return {('content_type','application/json')}
devopscmdb --> libs目录 --> handler.py文件
#注:定义处理异常的模块
from flask_restful import HTTPException
from libs.error_code import APIException
def default_error_hander(ex): #注:接收一个异常
if isinstance(ex, APIException): #注:如果它是APIException异常
return ex
if isinstance(ex, HTTPException): #注:如果它是HTTPException异常
code = ex.code
message = ex.description
status_code = 10001
return 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 #注:指定 重写的 自定义异常
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 Blueprint
class 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_bp
v1_bp = NestableBlueprint("v1",__name__, url_prefix="/v1/api/") #注:
v1_bp.register_blueprint(server_bp)
devopscmdb --> router目录 --> init.py文件
from router.v1 import v1_bp
def 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地址信息
参考博文 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
#注:在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 requests
def get_servers():
"""
从cmdb-api获取要采集哪些机器的数据数据
:return:
"""
# 从接口获取数据
from settings import API
content = requests.get(API).text
datas = 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
def copy_file(host,path): #注:修改端口 2233
import os
os.system("scp -rq -P 2233 cmdbclient2020 {host}:{path}".format(host=host, path=path))
def ssh2(ip,sn,run_cmd,env_cmd): #注:修改端口 2233
try: ……
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]#
#注:使用APIToken 保存授权密钥 授权的key值
#注:模型放在devopscmdb --> model目录 --> user.py文件下
devopscmdb --> model目录 --> user.py文件下
#注:输入以下全部代码
from libs.enums import MethodType
class 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 #注:导入md5
def api_authorize(): #注:复制粘贴以下全部代码
params = request.args
appid = 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_appid
user_secretkey = api_token.api_token_secretkey
user_sign = user_appid + salt + user_secretkey
m1 = md5()
m1.update(user_sign.encode(encoding='utf8'))
user_sign = m1.hexdigest()
if sign != user_sign:
raise APIAuthorizedException()
else:
return True
def has_permission(api_token, url, method): #注:复制粘贴以下全部代码
"""权限该api是否有指定url和指定方法的权限"""
# 从服务端查找appid及对应的秘钥
mypermission = method + url
all_permissions = [permission.api_permission_method_type.name + permission.api_permission_url for permission in
api_token.permissions]
if mypermission not in all_permissions:
raise APIAuthorizedException(message="没有当前接口的权限")
return True
devopscmdb --> libs目录 --> error_code.py文件下
#注:认证失败的返回信息
class APIAuthorizedException(APIException): #注:用户认证失败的自定义异常,继承APIException
message = "用户认证失败"
status_code = 10004 #注:给应用的返回码
code = 401 #注:给http的返回码
devopscmdb --> v1目录 --> server.py文件下
#注:加入认证
from libs.authorize import api_authorize
class 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 md5
def get_servers():
"""
从cmdb-api获取要采集哪些机器的数据数据
:return:
"""
# 从接口获取数据
from settings import API, APPID, SECRETKEY
salt = random.randint(32768, 65536)
sign = APPID + str(salt) + SECRETKEY
m1 = 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).text
datas = 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