day054 Flask_数据库,其他

今天的主要内容有:数据库迁移;邮件扩展,蓝图,单元测试以及RESTful。

数据库迁移

  • 在命令行使用Flask-Migrate包中的命令对数据库进行增删改的操作
  • 需要先在虚拟环境中安装Flask-Migigrate

    pip install flask-migrate

  • 需要使用flask-migrate中的Migrate类以及MigrateCommand类,前者负责关联app和数据库实例,后者包含了一些执行命令

  • 为什么要使用flask-migrate迁移数据库操作

    • 之前的操作是先用drop_all()将数据库清空,再用create_all()更新新的数据到数据库,这样操作是危险的,且没有记录。在实际工作中,大多数是更新数据库,但是不会删除数据
    • 可以保存每一次操作记录,像git一样记录每一次迁移信息
    • 可以返回之前的版本,也可以从旧的版本升级到新的版本,注意从旧版本升级到新的版本数据可能会丢失,所以尽量只执行更新数据库命令(db upgrade)

迁移步骤

  • 配置阶段

    1. 从flask_migrate包中导入Migrate,MigrateCommand

    from flask_migrate import Migrate,MigrateCommand

    1. 将flask的实例和qlalchemy数据库实例用Migrate()关联起来

    migrate = Migrate(app,db)

    1. 在flask_Script中添加一个db命令

    manager.add_command('db',MigrateCommand)

  • 执行阶段

    1. 初始化化Migrations文件夹

    python database.py db init

    扫描二维码关注公众号,回复: 418835 查看本文章
    1. 创建迁移文件

    python database.py db migrate -m 'initial migration'

    1. 执行迁移

    python database.py db upgrade

  • 完整代码

 #coding=utf-8
from flask import Flask

from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate,MigrateCommand
from flask_script import Shell,Manager

app = Flask(__name__)
manager = Manager(app)

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/Flask_test'
db = SQLAlchemy(app)

#第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例
migrate = Migrate(app,db) 

#manager是Flask-Script的实例,这条语句在flask-Script中添加一个db命令
manager.add_command('db',MigrateCommand)

#定义模型Role
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')

    #repr()方法显示一个可读字符串,
    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() 
  • 命令行迁移命令

  • 初始化迁移文件夹

# 初始化迁移文件夹.png

  • 生成迁移文件

#  生成迁移文件.png

  • 迁移文件

# 迁移文件.png

  • 迁移完成后,数据库结果

这里写图片描述

返回之前的版本

  • 可以根据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

  • 3 配置邮箱
app.config['MAIL_SERVER'] = "smtp.126.com"
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = "[email protected]"
app.config['MAIL_PASSWORD'] = "heima666"
app.config['MAIL_DEFAULT_SENDER'] = 'FlaskAdmin<[email protected]>'
  • 4 将app与Mail关联,生成邮箱对象

mail = Mail(app)

  • 5 用Message设置邮件发送内容

msg = Message('这是邮件的主题', recipients=['[email protected]'],body='This is flask mail')

- 6 发送邮件

mail.send(msg)

  • 完整代码
#coding:utf-8
from flask import Flask
from flask_mail import Mail, Message

app = Flask(__name__)

# 配置邮件:服务器/端口/安全套接字层/邮箱名/授权码
app.config['MAIL_SERVER'] = "smtp.126.com"
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = "[email protected]"
app.config['MAIL_PASSWORD'] = "heima666"
app.config['MAIL_DEFAULT_SENDER'] = 'FlaskAdmin<[email protected]>'

mail = Mail(app)


@app.route('/')
def hello_world():
    return '<a href="/send_mail">发送邮件</a>'


@app.route('/send_mail')
def send_mail():
    msg = Message('这是邮件的主题', recipients=['[email protected]'],body='This is flask mail')
    mail.send(msg)
    return '已发送邮件'


if __name__ == '__main__':
    app.run(debug=True)

蓝图

  • 蓝图(BluePrint)是一个存储操作方法的容器。
  • 这些操作方法在Blueprint被注册到应用之后,就可以被调用。Flask可以通过Blueprint来组织URL以及处理请求

  • 属性:

    • 一个应用可以有多个blueprint
    • 可以将一个blueprint注册到任何一个未使用的url下
    • 在一个应用中,一个模块可以注册多次
    • Blueprint可以拥有自己的模板,静态文件或者其他的通用操作方法,并不是必须要实现应用的视图和函数的
    • 在一个应用初始化时,就应该注册要使用的Blueprint
    • blueprint不是一个完整的应用,它不能独立于应用运行,必须要注册到某个应用中

使用蓝图的步骤

  • 1.创建一个蓝图对象

admin=Blueprint('admin',__name__)

  • 2.在这个蓝图对象上进行操作,注册路由,指定静态文件夹,注册模板过滤器
@admin.route('/')
def admin_home():
    return 'admin_home'
  • 3.在应用对象上注册这个蓝图对象

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):
        pass

    #该方法会在测试代码执行完后执行,方法名为固定写法
    def tearDown(self):
        pass
  • 3 在测试类中,编写测试代码
import unittest
class TestClass(unittest.TestCase):

    #该方法会首先执行,相当于做测试前的准备工作
    def setUp(self):
        pass

    #该方法会在测试代码执行完后执行,相当于做测试后的扫尾工作
    def tearDown(self):
        pass
    #测试代码
    def test_app_exists(self):
        pass

RESTful

  • REST:具象状态传输。一般解释为“表现层状态转换”
  • RETT是设计风格而不是标准。是指客户端和服务器的交互形式。我们需要关注的重点是如何设计REST风格的网络接口。

如何设计符合RESTful风格的API

  • 1.域名
    将api部署在专用域名下:

http://api.example.com

或者将api放在主域名下:

http://www.example.com/api/

  • 2.版本
    将API的版本号放在url中:
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
  • 4.使用标准的HTTP方法

对于资源的具体操作类型,由HTTP动词表示。 常用的HTTP动词有四个。

GET     SELECT :从服务器获取资源。
POST    CREATE :在服务器新建资源。
PUT     UPDATE :在服务器更新资源。
DELETE  DELETE :从服务器删除资源。

示例

#获取指定商品的信息

GET http://www.example.com/goods/ID

#新建商品的信息

POST http://www.example.com/goods

#更新指定商品的信息

PUT http://www.example.com/goods/ID

#删除指定商品的信息

DELETE http://www.example.com/goods/ID
  • 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://www.example.com/goods

#返回单个商品

GET    http://www.example.com/goods/cup

#返回新生成的商品

POST   http://www.example.com/goods

#返回一个空文档

DELETE http://www.example.com/goods
  • 9 使用链接关联相关的资源
    在返回响应结果时提供链接其他API的方法,使客户端很方便的获取相关联的信息。

  • 10 其他
    服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

猜你喜欢

转载自blog.csdn.net/michael_cool/article/details/79679932