作者:loassde_392 | 来源:互联网 | 2023-10-10 20:04
今天的主要内容有:数据库迁移;邮件扩展,蓝图,单元测试以及RESTful。
数据库迁移
- 在命令行使用Flask-Migrate包中的命令对数据库进行增删改的操作
需要先在虚拟环境中安装Flask-Migigrate
pip install flask-migrate
需要使用flask-migrate中的Migrate类以及MigrateCommand类,前者负责关联app和数据库实例,后者包含了一些执行命令
为什么要使用flask-migrate迁移数据库操作
- 之前的操作是先用drop_all()将数据库清空,再用create_all()更新新的数据到数据库,这样操作是危险的,且没有记录。在实际工作中,大多数是更新数据库,但是不会删除数据
- 可以保存每一次操作记录,像git一样记录每一次迁移信息
- 可以返回之前的版本,也可以从旧的版本升级到新的版本,注意从旧版本升级到新的版本数据可能会丢失,所以尽量只执行更新数据库命令(db upgrade)
迁移步骤
配置阶段
- 从flask_migrate包中导入Migrate,MigrateCommand
from flask_migrate import Migrate,MigrateCommand
- 将flask的实例和qlalchemy数据库实例用Migrate()关联起来
migrate = Migrate(app,db)
- 在flask_Script中添加一个db命令
manager.add_command('db',MigrateCommand)
执行阶段
- 初始化化Migrations文件夹
python database.py db init
- 创建迁移文件
python database.py db migrate -m 'initial migration'
- 执行迁移
python database.py db upgrade
完整代码
from flask import Flaskfrom flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Managerapp = Flask(__name__)
manager = Manager(app)app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test'
db = SQLAlchemy(app)
migrate = Migrate(app,db)
manager.add_command('db',MigrateCommand)
class Role(db.Model):__tablename__ = 'roles'id = db.Column(db.Integer, primary_key=True)name = db.Column(db.String(64), unique=True)user = db.relationship('User', backref='role')def __repr__(self):return 'Role:'.format(self.name)
class User(db.Model):__talbe__ = 'users'id = db.Column(db.Integer, primary_key=True)username = db.Column(db.String(64), unique=True, index=True)role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))def __repr__(self):return 'User:'.format(self.username)if __name__ == '__main__':manager.run()
返回之前的版本
- 可以根据history命令找到版本号,然后传给downgrade命令
- 找到版本号
python app.py db history
python app.py db downgrade 版本号
- 注意回滚到之前的版本,再次更新到新的版本,数据可能会丢失,所以尽量避免删除数据,而是去更新数据
邮件扩展
- 通过Flask_Mail拓展包,可以在Flask程序中发送邮件
- 原理:Flask-mail连接到简单邮件发送协议(Simple Mail Transfer Protocol,SMTP)服务器 ,并把邮件交给服务器发送
步骤
- 1 设置邮箱授权码,开启邮箱SMTP服务设置(同django一样)
- 2 从flask_mail中导入 Mail,Message
from flask_mail import Mail, Message
app.config['MAIL_SERVER'] = "smtp.126.com"
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = "huidongpeng@126.com"
app.config['MAIL_PASSWORD'] = "heima666"
app.config['MAIL_DEFAULT_SENDER'] = 'FlaskAdmin'
- 4 将app与Mail关联,生成邮箱对象
mail = Mail(app)
msg = Message('这是邮件的主题', recipients=['huidongpeng@126.com'],body='This is flask mail')
- 6 发送邮件
mail.send(msg)
from flask import Flask
from flask_mail import Mail, Messageapp = Flask(__name__)
app.config['MAIL_SERVER'] = "smtp.126.com"
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = "huidongpeng@126.com"
app.config['MAIL_PASSWORD'] = "heima666"
app.config['MAIL_DEFAULT_SENDER'] = 'FlaskAdmin'mail = Mail(app)@app.route('/')
def hello_world():return '发送邮件'@app.route('/send_mail')
def send_mail():msg = Message('这是邮件的主题', recipients=['huidongpeng@126.com'],body='This is flask mail')mail.send(msg)return '已发送邮件'if __name__ == '__main__':app.run(debug=True)
蓝图
使用蓝图的步骤
admin=Blueprint('admin',__name__)
- 2.在这个蓝图对象上进行操作,注册路由,指定静态文件夹,注册模板过滤器
@admin.route('/')
def admin_home():return 'admin_home'
app.register_blueprint(admin,url\_prefix='/admin')
单元测试
- 所谓单元测试,就是用代码测试代码
- 实际上就是一些‘断言’(assert代码)
- 为什么要进行单元测试?
- 好的程序必须能经得起各种测试,测试是软件开发中必须且极为重要的步骤。成型的应用,功能很多。程序人员每编写一段代码,完成一个小功能就应该进行相应的测试工作,这种面向功能单一的小模块进行测试的过程称为单元测试。这是每一个合格的程序人员都要掌握的基本技能。
断言方法
- 类似一个判断语句
assert expression 'AssertionError'
if not expression: raise AssertionError
assertEqual 如果两个值相等,则pass
assertNotEqual 如果两个值不相等,则pass
assertTrue 判断bool值为True,则pass
assertFalse 判断bool值为False,则pass
assertIsNone 不存在,则pass
assertIsNotNone 存在,则pass
单元测试步骤
- 1 定义一个类,继承自uniyyest.TestCase
import unittest
class TestClass(unitest.TestCase):pass
- 2 在测试类中,定义两个固定写法的测试方法
import unittest
class TestClass(unittest.TestCase):def setUp(self):passdef tearDown(self):pass
import unittest
class TestClass(unittest.TestCase):def setUp(self):passdef tearDown(self):passdef test_app_exists(self):pass
RESTful
- REST:具象状态传输。一般解释为“表现层状态转换”
- RETT是设计风格而不是标准。是指客户端和服务器的交互形式。我们需要关注的重点是如何设计REST风格的网络接口。
如何设计符合RESTful风格的API
- 1.域名
将api部署在专用域名下:
http://api.example.com
或者将api放在主域名下:
http://www.example.com/api/
http://www.example.com/app/1.0/info
http://www.example.com/app/1.2/info
- 3.路径
路径表示API的具体网址。每个网址代表一种资源。 资源作为网址,网址中不能有动词只能有名词,一般名词要与数据库的表名对应。而且名词要使用复数。
错误示例:
http://www.example.com/getGoods
http://www.example.com/listOrders
正确示例:
#获取单个商品http://www.example.com/app/goods/1
#获取所有商品http://www.example.com/app/goods
对于资源的具体操作类型,由HTTP动词表示。 常用的HTTP动词有四个。
GET SELECT :从服务器获取资源。
POST CREATE :在服务器新建资源。
PUT UPDATE :在服务器更新资源。
DELETE DELETE :从服务器删除资源。
示例
#获取指定商品的信息GET http:#新建商品的信息POST http:#更新指定商品的信息PUT http:#删除指定商品的信息DELETE http:
- 5.过滤信息
如果资源数据较多,服务器不能将所有数据一次全部返回给客户端。API应该提供参数,过滤返回结果。 实例:
#指定返回数据的数量http://www.example.com/goods?limit=10
#指定返回数据的开始位置http://www.example.com/goods?offset=10
#指定第几页,以及每页数据的数量http://www.example.com/goods?page=2&per_page=20
- 6.状态码
服务器向用户返回的状态码和提示信息,常用的有
0 OK :服务器成功返回用户请求的数据
201 CREATED :用户新建或修改数据成功。
202 Accepted:表示请求已进入后台排队。
400 INVALID REQUEST :用户发出的请求有错误。
401 Unauthorized :用户没有权限。
403 Forbidden :访问被禁止。
404 NOT FOUND :请求针对的是不存在的记录。
406 Not Acceptable :用户请求的的格式不正确。
500 INTERNAL SERVER ERROR :服务器发生错误
- 7.错误信息
一般来说,服务器返回的错误信息,以键值对的形式返回。
{error: 'Invalid API KEY'
}
- 8.响应结果
针对不同结果,服务器向客户端返回的结果应符合以下规范。
#返回商品列表GET http:#返回单个商品GET http:#返回新生成的商品POST http:#返回一个空文档DELETE http: