- 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kun1280437633/article/details/80252011
1、数据库的迁移
在开发中如果一旦模型更改,也就意味着数据库中表的字段已经更改了,如果删掉数据库中所有的表有可能导致数据丢失.解决办法:使用数据库迁移。
迁移流程:依赖于两个扩展包Flask_migrate,Flask_script
(1)生成版本记录文件 python xxxx.py db init
(2)生成迁移脚本 python xxxx.py db migrate -m '注释'
(3)更新数据库 python xxxx.py db upgrade [version]
降低: python xxxx.py db downgrade [version] # 谨慎操作(4)查看当前版本:python xxxx.py db current
查看版本历史:python xxxx.py db history
代码:
from flask_script import Manager
from flask import Flask
from flask_migrate import Migrate,MigrateCommand
from flask.ext.sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.debug = True
#数据库配置信息
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@localhost:3306/person'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
manager = Manager(app)
#迁移工作
Migrate(app, db)
#给manager管理对象,设置操作命令
manager.add_command('db', MigrateCommand)
#模型类
class Person(db.Model):
__tablename__ = 'persons'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
age = db.Column(db.Integer)
@app.route('/')
def index():
pass
if __name__ == '__main__':
# app.run(debug=True)
manager.run()
2、发送邮件
要想发送邮件要用到flask_mai,这是发送邮件的扩展包
使用流程:
(1)进行配置,配置邮箱的账号,授权码,端口,ip..
(2)创建邮件客户端,关联app
(3) 创建消息体
(4)使用客户端, 发送消息体
代码:
import threading
from flask import Flask,url_for
from flask_mail import Mail,Message
app = Flask(__name__)
#设置配置信息
app.config['MAIL_SERVER'] = 'smtp.163.com' #邮件服务器的地址
app.config['MAIL_USERNAME'] = '[email protected]' #邮件用户名
app.config['MAIL_PASSWORD'] = 'python2018' #授权码
app.config['MAIL_PORT'] = 465 # 网易邮箱固定发送端口
app.config['MAIL_USE_SSL'] = True #安全加密套接字传输
app.config['MAIL_DEFAULT_SENDER'] = '[email protected]' #默认的邮件发送者
#创建邮件客户端
mail = Mail(app)
@app.route('/')
def index():
return "<a href = '%s'>发送</a>"%url_for('send_mail')
@app.route('/send_mail')
def send_mail():
#创建消息体
message = Message()
message.subject = 'kunhan'
message.recipients = ['[email protected]'] #邮件接受者
message.html = "<h1>I love you</h1>"
thread = threading.Thread(target=async_send,args=(app,message))
thread.start()
mail.send(message)
return '发送成功'
def async_send(app, message):
with app.app_context():
mail.send(message)
import time
time.sleep(10)
if __name__ == '__main__':
app.run(debug=True)
3、模块化开发
为什么要学习模块化开发, 真实的使用场景中业务逻辑是很复杂的,不可能把所有的内容都写在一个视图函数,一个模块中
解决方法有两种方式:
(1)模块化开发方式1:先导入,后装饰(缺点: 一旦视图函数名字发生改变,就需要更改装饰的地方)
代码:
from flask import Flask
from test3_user import get_user
app = Flask(__name__)
#后装饰
app.route('/user')(get_user)
@app.route('/')
def get_product():
return '获取商品信息'
@app.route('/index')
def get_index():
return '获取首页信息'
if __name__ == '__main__':
print app.url_map
app.run(debug=True)
test3_user.py文件 代码:
# coding:utf8
def get_user():
return 'hello'
(2)模块化开发方式2:使用蓝图(blueprint)
注意点:循环导入问题,让一边断开
蓝图使用流程:
(1) 创建蓝图对象
(2)再使用蓝图对象装饰视图函数
(3)将蓝图对象注册到app中 代码:
from flask import Flask
from test4_product import pro
app = Flask(__name__)
# (3)将蓝图对象注册到app中
app.register_blueprint(pro)
@app.route('/')
def index():
return 'helloworld'
if __name__ == '__main__':
print app.url_map
app.run(debug=True)
test4_product.py文件代码:
#coding:utf8
# 蓝图使用流程:
# (1) 创建蓝图对象
# (2) 再使用蓝图对象装饰视图函数
# (3) 将蓝图对象注册到app中
from flask import Blueprint
# (1)创建蓝图对象
#参数1表示蓝图的名字, 参数2表示蓝图所在的模块
pro = Blueprint('product', __name__)
print __name__
# (2)再使用蓝图对象装饰视图函数
@pro.route('/get_product')
def get_product():
return 'this is product'
代码2:
# coding:utf8
from flask import Flask
from cart import abc
app = Flask(__name__)
app.register_blueprint(abc)
@app.route('/')
def index():
return 'hi'
if __name__ == '__main__':
print app.url_map
app.run(debug=True)
cart文件夹下有__init__.py文件代码:
#coding:utf8from flask import Blueprint
#1.创建蓝图对象
#url_prefix:用来标记当前的视图函数是属于哪一个模块下的
#template_folder: 当前蓝图的模板文件
#如果模板文件的名字和外层模板文件名字是一样的默认访问的就是外层模板文件名字
abc = Blueprint('def', __name__,url_prefix='/cart',template_folder='xxx')
from . import views
cart文件夹下有views.py文件代码:
#coding:utf8
from . import abc
from flask import render_template
# 2.使用蓝图对象装饰视图函数
@abc.route('/work')
def work():
return 'hello'
@abc.route('/price')
def get_cart_price():
return render_template('cart01.html')
cart文件夹下xxx文件夹下cart01.html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>I love you</h1>
</body>
</html>
4、断言(assert)
断言(assert):用来判断程序在某个阶段的时候,值和预期的是一样的效果,经常配合单元测试使用
格式:assert boolean表达式A, 异常说明1
执行流程:
如果表达式A为True,正常往低下走
如果表达式A为Flase,立刻停止,跑出异常说明1
代码:
def div(num1, num2):
assert isinstance(num1, int), Exception('num1必须是一个数字')
assert isinstance(num2, int), Exception('num2必须是一个数字且不能为0')
return num1/num2
print div(100, 50)
# print div('100', 50)
5、测试
常见的测试有:系统测试,集成测试,压力测试,暴力测试。
单元测试:一般中大型公司会用到,对某一块单独的功能写代码测试所有的可能性
测试流程:
(1) 自定义测试类,继承自unittest.TestCast
(2) 编写测试方法,测试方法必须以test开头
(3) 在方法中编写业务逻辑测试
注意点:
在测试类中有两个默认的方法
setup:一旦测试案例执行的时候首先会走这个方法,
teardown:一旦测试案例结束之后会走该方法案例:测试一段登录功能
(1) 服务器的登录功能代码
(2)测试案例代码
代码:
import json
from unittest import TestCase
from flask import Flask
from test8 import app
class LoginTest(TestCase):
# 测试案例执行的时候,先走该方法,适合做初始化操作
def setUp(self):
# 1.创建测试客户端
self.client = app.test_client()
# 2.设置测试模式
# 好处: 一旦出错之后,不会一直报测试案例出错, 会准确定位错误位置
app.testing = True
# 1.测试账号密码为空的情况
def testlogin(self):
# 1.获取测试客户端
# client = app.test_client()
# 2.发送请求
response = self.client.post('/login',data = {'username':'','password':''})
# 3.解析数据
json_data = response.data
dict_data = json.loads(json_data)
#校验
self.assertIn('code',dict_data)
self.assertEqual(dict_data['code'],1,'code的值必须为1')
# 2.对账号密码正确性验证
def test_login_func_correct(self):
# 1.获取测试客户端
# client = app.test_client()
# 2.发送请求
response = self.client.post("/login", data={"username": "admin", "password": "123"})
# 3.解析数据
json_data = response.data
dict_data = json.loads(json_data)
# 4.校验
self.assertIn("code", dict_data)
# self.assertEqual(dict_data["code"],2)
self.assertEqual(dict_data["code"], 0)
test8.py代码:
#coding:utf8
"""
状态码说明:code: 1 表示账号或者密码为空
code: 0 表示账号密码正确
code: 2 表示账号密码错误
"""""from flask import Flask,jsonify,request
app = Flask(__name__)
@app.route('/login', methods=['POST'])
def login():
# 1.获取参数,用户名,密码
username = request.form.get('username')
password = request.form.get('password')
# 测试调试模式
# 1 / 0
# 2.校验
# 2.1验证为空的情况
if not all([username,password]):
return jsonify({'code':1, 'msg' : '参数不完整'})
# 2.2验证账号密码的正确性
if username == 'admin' and password == '123':
# return jsonify(code=0, msg='账号密码正确')
return jsonify({'code':0,'msg':'账户密码正确'})
else:
return jsonify({'code':2,'msg':'账户或密码错误'})
if __name__ == '__main__':
app.run(debug=True)
6、测试数据库
流程:
(1)定义类,继承自TestCast
(2)编写方法:setup、test开发的方法、teardown
setup:初始化操作,比如:设置测试客户端,测试模式,数据库配置,表的创建
test开头方法: 测试具体的业务功能
teardown: 关闭数据链接,删除表
代码:
from unittest import TestCase
from library import db,app,Author
class Database(TestCase):
def setUp(self):
# 设置测试数据库flaskdb2_test为新建测试数据库,不要在原数据库操作
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@localhost:3306/flaskdb2_test'
app.testing = True
db.create_all()
# 测试数据库添加数据的测试
def test_database_add_data(self):
#创建作者对象
author = Author(name ='xiaohan')
db.session.add(author)
db.session.commit()
import time
time.sleep(10)
#取出来
author = Author.query.filter(Author.name == 'xiaohan').first()
#断言一定有内容
self.assertIsNotNone(author)
def tearDown(self):
db.session.remove()
db.drop_all()
library.py文件代码参考上个博客的图书馆程序
7、部署
使用流程:
(1) 安装Gunicorn;pip install gunicorn
(2) 配置nginx,配置我们自己的服务器
(3) 启动
gunicorn -w 4 -b 127.0.0.1:5000 --access-logfile ./logs/log1 要运行的模块名字:app
w: worker, 表示要开启几条进程
b: bind, 绑定那个ip和端口
--access-logfile ./logs/log1: 要将用户访问的内容写到哪个文件里面去
要运行的模块名字:app:要运行的时候哪一个模块里面的应用程序