## 简介
### 项目目录
![image-20210207111647955](http://qiniu.rainna.xyz/image-20210207111647955.png)
1 2 3
| static 静态文件存放路径 template 模板文件存放路径 app.py 可改名,编写网页逻辑
|
### HelloWorld
1 2 3 4 5 6 7 8 9
| from flask import Flask app = Flask(__name__)
@app.route('/') def hello_world(): return 'Hello World!'
if __name__ == '__main__': app.run()
|
## 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| from flask import Flask
app = Flask("myApp", static_folder="static", template_folder="templates")
@app.route('/config') def hello_world(): return 'Hello World!'
if __name__ == '__main__': app.run(debug=True, port=8080, host="0.0.0.0")
|
- 或在终端运行时配置
1 2
| > set FLASK_ENV=development > flask run
|
- pycharm的flask模板运行flask项目会有很多问题,用纯python模板!!
### Flask类
1 2 3 4
| root_path static_folder static_url_path template_folder
|
- `import_name`: 应用程序的另一种实例路径。默认情况下,包或模块旁边的文件夹 instance 被假定为实例路径。
- `root_path`: 默认情况下,flask将自动计算引用程序根的绝对路径, 由import_name 决定.
- **instance_path** 和 **instance_relative_config** 共同作用,可以改变由import_name 实例路径, 掩藏敏感配置[1](https://blog.csdn.net/f704084109/article/details/80646937#fn:3)
- `static_folder `指定了静态资源的路径. 默认情况下,底层实际上是通过static_folder 确定了 static_url_path,
然后通过 self.static_url_path + /\
注册的静态资源路由.
- 当static_url_path 和 static_folder 同时存在时, 系统会直接使用 self.static_url_path + /\注册的静态资源路由.
- static_host 和 host_matching 同时作用可以改变静态资资源存放的主机, 既可以从资源服务器读取资源.
- static_url_path / static_folder / static_host / host_matching 四者结合使用可以访问资源服务器上的指定文件夹下的资源
- template_folder 设置模板文件名称
- subdomain_matching 支持子域名, 结合app.config[“SERVER_NAME”] = “域名:端口” 使用.
## Request
### 获取请求数据
#### GET请求
> request.args
1 2 3 4 5 6 7 8 9
|
@app.route('/') def hello_world(): args = request.args print(args) return 'Hello World!'
|
> request.args.getlist
1 2 3 4 5 6 7 8 9 10
|
@app.route('/') def hello_world(): args_list = request.args.getlist('user') args_list_type = request.args.getlist('user', type=lambda x: int(x)+1) print(args_list_type) print(args_list) return 'Hello World!'
|
#### POST请求
> request.form
1 2 3 4 5 6 7 8 9 10
|
@app.route('/post/', methods=["POST"]) def hello_world(): data = request.form print(data) return 'Hello World!'
|
> request.form.getlist
1 2 3 4 5 6 7 8 9 10
|
@app.route('/post/', methods=["POST"]) def hello_world(): data = request.form data_list = request.form.getlist("username", type=lambda x: x + "~") print(data_list) print(data) return 'Hello World!'
|
> request.json
1 2 3 4 5 6 7
| @app.route('/json/', methods=["POST"]) def json_post(): data = request.json print(data) print(type(data)) return 'Hello World!'
|
> request.file
1 2 3 4 5 6 7 8 9 10
|
@app.route('/file', methods=["POST"]) def file_post(): file = request.files print(file) img = file.get("image") img.save(r"D:\Code\LearnCodes\Python\web_Flask\flasker\static\uploads\img.png") return 'Hello World!'
|
### 获取请求路径
> request.path
>
> request.full_path
>
> request.script_root
>
> request.url
>
> request.base_url
>
> request.url_root
1 2 3 4 5 6 7 8 9 10
|
@app.route('/') def hello_world(): path = request.path full_path = request.full_path print(path) print(full_path) return 'Hello World!'
|
***区别***:
假设您的应用程序正在以下应用程序根目录上侦听:
1
| http://www.example.com/myapplication
|
用户请求以下URI:
1
| http://www.example.com/myapplication/%CF%80/page.html?x=y
|
在这种情况下,上述属性的值如下:
| path | `u'/π/page.html'` |
| :---------- | --------------------------------------------------------- |
| full_path | `u'/π/page.html?x=y'` |
| script_root | `u'/myapplication'` |
| base_url | `u'http://www.example.com/myapplication/π/page.html'` |
| url | `u'http://www.example.com/myapplication/π/page.html?x=y'` |
| url_root | `u'http://www.example.com/myapplication/'` |
## Response
### Redirect
> 重定向,跳转到指定地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @app.route('/') def hello_world(): return 'hello world'
@app.route('/test1') def test1(): print('this is test1') return redirect(url_for('test2'))
@app.route('/test2') def test2(): return redirect("https:www.baidu.com")
@app.route('/redirected') def redirected(): print('重定向') return '重定向啦!!'
|
### Jinja2模板引擎
> render_template 渲染模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title> {% if page_title %} {{ page_title }} {% endif %} </title> </head> <body> {% block body %}{% endblock %} </body> </html>
|
1 2 3 4 5 6 7 8 9
|
{% extends "index.html" %}
{% block body %} {% for key in user_info %} <br>{{ key }}: {{ user_info[key] }} {% endfor %} {% endblock %}
|
1 2 3 4 5 6 7 8 9 10
| @app.route('/user') def user(): user_info = { 'name': 'letian', 'email': '[email protected]', 'age': 0, 'github': 'https://github.com/letiantian' } return render_template('block.html', page_title='i\'s info', user_info=user_info)
|
### 自定义错误页面
> 处理HTTP错误,可以使用`flask.abort`函数
1 2 3 4 5 6 7 8 9 10 11
| @app.route('/') def hello_world(): return 'hello world'
@app.route('/user') def user(): abort(401) print('Unauthorized, 请先登录')
|
默认效果:
![image-20210207164026415](http://qiniu.rainna.xyz/image-20210207164026415.png)
> 使用@app.errorhandler(状态码)来装饰一个函数用来处理对应的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @app.route('/') def hello_world(): return 'hello world'
@app.route('/user') def user(): abort(401) print('Unauthorized, 请先登录')
@app.errorhandler(401) def page_unauthorized(error): return render_template_string('<h1> Unauthorized </h1><h2>{{ error_info }}</h2>', error_info=error), 401
|
- 注: 被装饰的函数返回的是一个元组,401表示状态码,缺省为200
自定义效果:
![image-20210207164409794](http://qiniu.rainna.xyz/image-20210207164409794.png)
### Cookie
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| @app.route('/set') def login(): res = Response('add cookies') res.set_cookie(key='name', value='i', expires=time.time()+6*60) return res
@app.route('/show') def show(): return request.cookies.__str__()
@app.route('/del') def del_cookie(): res = Response('delete cookies') res.set_cookie('name', '', expires=0) return res
|
### Session
添加session会默认在cookie中添加sessionId字段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @app.route('/do_login', methods=['POST']) def do_login(): name = request.form.get('user_name') session['user_name'] = name return 'success'
@app.route('/show') def show(): return session['user_name']
@app.route('/logout') def logout(): session.pop('user_name', None) return redirect(url_for('login'))
|
## RestFul URL
将访问的url中部分作为函数参数,使得网页开发向软件开发靠拢的一种架构。
### 转换器的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
@app.route('/user/<username>') def user(username): print(username) return 'Hello World!' + str(username)
@app.route('/user/<int:page>') def pager(page): print(page) return 'Hello World!' + str(page)
@app.route('/page/<int:page_start>-<int:page_end>') def pager_range(page_start, page_end): print(page_start, page_end) return 'Hello World!' + str(page_start) + str(page_end)
|
- 注:装饰器中<>内的参数名要与视图函数形参名相同!参数个数也要对应
1 2 3 4 5 6 7 8
| 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 'path': PathConverter, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter,
|
### 自定义转换器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| from werkzeug.routing import BaseConverter from flask import url_for
class MyConverter(BaseConverter): def __init__(self, map_): super(MyConverter, self).__init__(map_) self.regex = "[123]"
def to_python(self, value): print("value" + value) if value.isalpha(): value += "100" elif value.isdigit(): value = int(value) + 100 return value
def to_url(self, value): print(value, "v") value = str(value) if value.isalpha(): value *= 2 elif value.isdigit(): value = int(value)*2 return str(value)
app.url_map.converters['add100'] = MyConverter
@app.route('/mypage/<add100:page>') def myPager(page): print("func" + str(page)) print(url_for("myPager", page=999)) return 'Hello World!' + str(page)
|
## 路由
### url_for
> 根据``endpoint`(默认为视图函数名)反转生成url
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @app.route('/') def hello_world(): pass
@app.route('/user/<name>') def user(name): pass
@app.route('/page/<int:num>',endpoint="myPage") def page(num): pass
@app.route('/test') def test(): print(url_for('hello_world')) print(url_for('user', name='i')) print(url_for('myPage', num=1, q='had10%3', words="haha")) print(url_for('static', filename='uploads/01.jpg')) return 'Hello'
|
### 蓝图
> `蓝图`是为了将路由和视图函数分写到多个文件,相当于Django的include。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| from flask import Blueprint
user_bp = Blueprint("user", __name__, url_prefix="/user")
@user_bp.route('/') def user_index(): return "hello!"
@user_bp.route("/user") def login(): return "please login"
@user_bp.route('/detail') def detail(): return "details"
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| from flask import Flask
from flasker.ForBlueprint.user.views import user_bp from flasker.config import BasicConfig
def create_app(): app = Flask(__name__) app.config.from_object(BasicConfig) app.register_blueprint(user_bp) return app
|
### url_map
> 查看当前的路由
1 2 3 4 5 6 7 8 9 10
| def create_app(): app = Flask(__name__) app.config.from_object(BasicConfig) app.register_blueprint(user_bp) print(app.url_map) return app
|