168 阅读9分钟

快速开始

安装flask

pip install flask

依赖

werkzeug:一个WSGI工具包(web服务网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为python语言定义的web服务器和web应用程序或框架之间的一种简单而通用的接口

jinja2:模板引擎

from flask import Flask # Flask是核心类

# 初始化application
app=Flask(__name__)

# 运行服务器
app.run()

定义路由

@app.router("/")
def index():
    return "hello world"

处理url和函数之间的绑定关系的程序叫做路由。

视图函数

处理url的逻辑和方法,就叫视图函数。

@app.router("/")
def index(): # 视图函数
    return "hello world"

请求

  1. 请求数据存在request里

image.png

  1. 获取请求数据

@app.route('/')
def index():
    args=request.args
    name=args.get("name")
    print(name)
    return 'Hello World!'

访问:http://127.0.0.1:5000/ name的值为None

访问:http://127.0.0.1:5000?name=joy name的值为joy

使用request.args.get(key)获取get请求的参数。

响应

return 后面是响应内容。 可以是json、html、html文件、str

  1. 字符串文本

    return 'Hello World!'

  2. html

    return '<h1>Hello html</h1>'

  3. html文件

    from flask import Flask,request,render_template
    
    @app.route('/')
    def index():
        return render_template("index.html")
    

    html文件需要放在templates文件夹下。

    why?app初始化时:

    template_folder="templates"

    image.png

    static_folder:项目静态文件放置,如css.image等

    static_url_path:前端访问时,告知静态文件存放的文件夹

    存储图片小技巧(页面展示图片、做个人博客图片等):

    将图片存储在static中,可以通过127.0.0.1:5000/static/hello.jpg访问图片

  4. json

MVC组成

  • model --》数据相关逻辑,sql

  • view --》前端内容,response html

  • control --》控制器,视图函数,作用:接收请求+响应结果

  • 控制器 Controller :负责转发请求、对请求进行处理

  • 视图 View:界面设计人员进行图形界面设计

  • 模型 Model:程序员编写程序应有的功能(实现算法等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)

    @app.route('/')
    def hello_world():  
        # 1. 接收参数
        # 2. 调用对应的函数去处理数据--》model
        # 3. 构建响应结果
        return 'Hello World!'
    

开启服务器

  1. 使用app.run()app.run(debug=True)调试模式,开启后代码修改后会自动重启服务。只能在测试、开发环境使用,不能在生产环节使用debug模式。

  2. 命令行运行:set FLASK_APP=app.pyflask run

比如host、post参数都在run里指定参数,但是他们也可以通过配置文件的形式来修改。

配置文件的必要性:

如果现在要部署给别人用,debug这样的东西就要关掉,port这些东西也又可能修改,那是不是上线以后再手动修改呢?

不是,而是通过配置文件,不同的环境我们使用不同的配置文件就可以了。

配置参数的方式:

  1. 字典、元组
  2. 反射 setattr\getattr
  3. config文件
  4. Config类 后面讲
### 配置项
app.config["DEBUG"]=True
app.config["PORT"]=5002

@app.route('/')
def index():
    args=request.args
    name=args.get("name")
    print(name)
    return 'Hello World!'


if __name__ == '__main__':
    app.run(debug=app.config["DEBUG"],port=app.config["PORT"])

注意事项

host

其他网络访问:0.0.0.0外部访问。所有人可访问。

固定的网络地址:192.168.1.23 ,指定访问

127.0.0.1 本机可访问

路由

处理URL和函数之间的关系的程序就叫做路由。

一、多URL的路由

一个函数上可以设置多个url路由规则。

@app.route('/hello/<name>')
@app.route('/hello')
@app.route('/')
def index():
    args = request.args
    name = args.get("name")
    print(name)
    return 'Hello World!'

还有其他的装饰器,视图函数装饰器应该放在最外层,不然不会生效。

二、路由动态参数

请求参数中传递参数:

@app.route('/cases')
def cases():
    id = request.args.get("id")
    return '正在执行什么啊{}'.format(id)

访问:http://127.0.0.1:5002/cases?id=2

路由上传递参数:(建议使用)

@app.route('/cases/<id>')
def index(id):
    print(id)
    return '正在执行{}'.format(id)

访问:http://127.0.0.1:5002/cases/2

规定入参的类型:

@app.route('/cases/<int:id>')
def index(id):
    print(id)
    return '{}是一个整数'.format(id)

支持的类型:

int 整数

float 浮点数

string 字符串,不可以包含斜杠

path 跟字符串的区别是,可以包含斜杠

uuid 特定格式字符串,通常是生成唯一id,uuid.uuid4() 导入uuid标准库 import uuid

三、路由重定向

访问/hello,/hello/的区别

@app.route('/cases')
def cases():
    return 'cases'

访问http://127.0.0.1:5002/cases 可以返回

访问http://127.0.0.1:5002/cases/ 404

@app.route('/cases/')
def cases():
    return 'cases'

访问http://127.0.0.1:5002/cases 可以返回

访问http://127.0.0.1:5002/cases/ 也可以返回

抓取接口请求,访问http://127.0.0.1:5002/cases 时,调起了两个请求,分别是/cases/cases/的.

image.png

状态码为308,永久重定向。重定向地址为Location的参数:http://127.0.0.1:5002/cases/

flask的哲学与灵活:

flask哲学:/cases/cases代表两个不同的url地址 flask灵活:定义路由/cases/,访问/cases时 会重定向到/cases/

四、路由注册机制

  1. 集中注册机制 (项目大,大量url,项目大时会分布到多个模块中,而把注册规则放到一个文件中)
def cases():
    return 'cases'

# 路由、view_fun参数绑定函数名
app.add_url_rule('/cases/', view_func=cases)
  1. 装饰器注册
@app.route('/cases/')
def cases():
    return 'cases'

app.route()实际也是调用的add_url_rule()方法

  1. app.url_map()

路由是处理URL和函数之间的关系的程序。绑定url和函数之间的关系关系都会单独命一个名字(这个东西就叫做端点) app.url_map()专门用来存储路由关系。

app = Flask(__name__)

print(app.url_map)


def cases():
    return 'cases'
app.add_url_rule('/cases/', view_func=cases)

print(app.url_map)

打印结果:

Map([<Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>])
Map([<Rule '/cases/' (GET, OPTIONS, HEAD) -> cases>,
 <Rule '/static/<filename>' (GET, OPTIONS, HEAD) -> static>])

在没有绑定路由时,咱们的路由关系就只有static的。 绑定路由后<Rule '/cases/' (GET, OPTIONS, HEAD) -> cases>端点名是cases,默认是使用视图函数的函数名作为端点名。(GET, OPTIONS, HEAD)表示支持的请求方式。

五、app.route()可配置的参数

  1. 添加mehtods参数:请求方式
@app.route('/', methods=["POST"])
def hello_world():
    return 'Hello World!'


def cases():
    return 'cases'


app.add_url_rule('/cases/', view_func=cases, methods=["POST"])

print(app.url_map)

修改了接口支持的请求方式:

Map([<Rule '/cases/' (OPTIONS, POST) -> cases>,
 <Rule '/' (OPTIONS, POST) -> hello_world>,
 <Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
  1. endpoint 修改路由Mapping地址对应视图函数的端点名
@app.route('/', methods=["POST"],endpoint="hello")
def hello_world():
    return 'Hello World!'
    
print(app.url_map)

<Rule '/' (POST, OPTIONS) -> hello>,

  1. redirect_to 重定向

一种是在app.route中的参数redirect_to,一种方式是在视图函数中return redirect方法。 区别,作为app.route参数redirect_to="/cases/"时,访问http://127.0.0.1:5000/ 时,程序不进入hello_world()函数中,作为return redirect("/cases/")访问http://127.0.0.1:5000/policy 时,会进入到视图函数policy()中

@app.route('/', methods=["GET", "POST"], endpoint="hello", redirect_to="/cases/")
def hello_world():
    print("进入hello_world")
    return 'Hello World!'


@app.route('/cases/', methods=["GET", "POST"], )
def cases():
    return 'cases'


@app.route('/policy', methods=["GET", "POST"], )
def policy():
    print("进入policy")
    return redirect("/cases/")
  1. defaults 默认值,经常用在动态参数上
@app.route('/',methods=["POST","GET"])
def index():
    return 'home'


@app.route('/cases',methods=["GET"],defaults={"id":3})
def cases(id):
    print(id)
    return redirect("/")

视图函数中可直接定义 id=3

视图函数的分离

大型项目中, 我们的架构:

  • 启动文件
  • 视图函数
  • 数据处理
  • view
  • 其他的帮助函数

可能出现的问题,模块间的相互调用,会造成循环调用,解决:就是使用时再调用。

视图函数

1. 什么是视图函数

什么是视图函数

视图函数里写什么

逻辑不应该太长,具体逻辑在另外的模块去封装。

能封装整理尽快,不要等到以后,以后太乱了不会再由耐心去整理。

url--》后端逻辑

2. 视图函数的形式

分请求方法

分请求单数复数

视图函数对应mvc的部分,不要越界

# 获取所有测试用例/获取单个测试用例

# 在同一个函数中处理
# @app.route('/project')
# def project():
#     if request.args.get("id") is None:
#         return "all projects"
#     else:
#         return "单个case"

# 在不同的函数中处理
@app.route('/projects')
def projects():
    return "all projects"


@app.route('/project/<id>')
def project(id):
    return "单个case"

# 不同的请求方法 GET POST PUT 是在一个函数中处理 还是不同的函数中处理
# 通常是放到同一个视图函数中处理(前后端不分离)

3. 什么是基于类的视图(可插拔视图)

从django学来的

4. 类的视图有什么好处

前后端分离适用 ,前后端不分离的 常用适用一个函数处理get/post不同的请求方法

  • 类是可以继承的
  • 代码可以复用
  • 可以定义多种行为

5. 可插拔视图

类视图有个固定的dispatch_request方法。

类视图里不能通过装饰器进行路由注册。

from flask.views import view
app =Flask(__name__)

class UserView(view):
    method = ["GET","POST"]
    
    def dispatch_request(self):
        return '{}到hello'.format(request.method)

add.add_url_rule("/",view_function=UserView.as_view('user'))

把类当成方法在使用。

from flask import Flask, request
from flask.views import View

app = Flask(__name__)


class Project(View):
    # 也可以把请求方法作为类的属性
    # methods=["POST","GET"]
    
    # get方法
    def get(self):
        return "一些get方法逻辑"

    # post方法
    def post(self):
        return "一些post方法逻辑"

    def dispatch_request(self): # 分配请求
        dispatch_pattern = {"GET": self.get, "POST": self.post}
        # 获取请求方法
        method = request.method
        print(method)
        # 调用get/post方法
        return dispatch_pattern.get(method)()


app.add_url_rule("/project",
                 view_func=Project.as_view("project"),
                 # 默认是get方法
                 methods=["POST","GET"]
                 )

6. 对不同的请求方法进行不同的处理

见上小节

7.methodView

methodView继承了View,实现了dispatch_request方法,所以继承methodView,可以直接写get、post方法等,不需要再写dispatch_request方法。

from flask import Flask
from flask.views import MethodView

app = Flask(__name__)


class ProjectView(MethodView):# 继承MethodView,不用使用
    # get方法
    def get(self):
        return "一些get方法逻辑1111"

    # post方法
    def post(self):
        return "一些post方法逻辑2222"


app.add_url_rule("/project",
                 view_func=ProjectView.as_view("project"),
                 # 默认是get方法
                 methods=["POST", "GET"]
                 )

8.methodview的例子

image.png

from flask import Flask
from flask.views import MethodView

app = Flask(__name__)


class ProjectView(MethodView):  # 继承MethodView,不用使用
    # get方法
    def get(self, project_id):
        if project_id is None:
            return "获取项目列表"
        else:
            return "显示项目:{}".format(project_id)

    # post方法
    def post(self, project_id):
        return "创建一个项目:{}".format(project_id)

    def put(self, project_id):
        return "更新项目:{}".format(project_id)

    def delete(self, project_id):
        return "删除项目:{}".format(project_id)


# 有参数、无参数的分开注册
f = ProjectView.as_view("projects")
app.add_url_rule("/projects/<project_id>",
                 view_func=f,
                 methods=["GET","POST", "PUT", "DELETE"]
                 )
app.add_url_rule("/projects",
                 view_func=f,
                 defaults={"project_id": None},
                 methods=["GET"]
                 )

请求和响应

1.请求对象

获取前端传过来的请求数据是后端服务来管理的。Flask内置实现了,使用from flask import request导入

  • get请求

    request.args

    @app.route('/projects')
    def projects():
        args = request.args
        print(args.get("id")) 
        return args
    

    访问:http://127.0.0.1:5002/projects?id=2 ,获取?后面的参数

    args.get("id") ==>2

  • 表单

    form_data=request.form

  • json/header

    json_data=request.json

  • file file_data =request.files

  • ajax请求

image.png

MVC

配置文件

模版引擎

表单验证

WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证。

安装:pip3 install wtforms

现在使用flask拓展 Flask-WTF,Flask-WTF 提供了简单地 WTForms 的集成

全局变量

数据库和模型

ORM模型数据库操作

image.png

image.png

安装 pip install sqlalchemy


from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)
app.config["DEBUG"]=True
# SQLALCHEMY_DATABASE_URI格式为:数据库类型+数据库引擎+用户名+密码@ip:port/数据库
app.config["SQLALCHEMY_DATABASE_URI"]="mysql+pymysql://root:@localhost:3306/test"
# app.config["SQLALCHEMY_BINDS"]=False
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"]=False
db = SQLAlchemy(app)  # 初始化数据库对象 、绑定app


# 设计表
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)


def create_all():
    return db.create_all()


create_all() #生成表

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

使用命令行创建数据库:

set Flask_APP=app.py

flask shell进入flask shell ,到app的环境中

from app import db导入db

db.create_all() 创建表

使用migrate创建:

为什么用migrate 1.迁移时更加方便 2.动态修改数据库结构


app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"]='mysql+pymysql://root:{}@127.0.0.1:3306/test'.format("123456")
db = SQLAlchemy(app)
migrate=Migrate(app,db)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)

安装:pip install flask-migrate

初始化命令:flask db init,会生成一个migrations文件

命令:flask db migrate,在migrations/versions下生成一些创建数据库的脚本

更新表:flask db upgrade

删除表:flask db downgrade

使用代码创建:

ORM模型SQLAlchemy

核心类

线程隔离

大型应用

注册

日志处理