1+1=10

记记笔记,放松一下...

Python flask入门笔记(六)

视图类View

当flask程序收到一个客户端请求,需要一个 view_func进行处理。前面我们一直老老实实定义处理函数,而后用装饰器route()或者add_url_rule()进行注册。

1
2
3
4
5
6
7
from flask import Flask
app = Flask(__name__)

@app.route('/')
@app.route('/home')
def index():
    return "Hello World!"

除了这个方式,flask还支持视图类View:

  • 派生 Flask.views.View
  • 定义类方法 dispatch_request
  • 使用add_url_url注册绑定
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from flask import Flask, views

app = Flask(__name__)

class MyView(views.View):
    def dispatch_request(self):
        return 'Hello World!'


app.add_url_rule('/', view_func=MyView.as_view('myview'))
app.add_url_rule('/home', view_func=MyView.as_view('myview2'))

使用一个类,比一个函数有什么好处?

  • 类支持继承,可以把共性的东西放到基类
  • 比如flask中,MethodView是View的派生类

as_view

视图类不能使用装饰器,视图类不能直接注册,需要通过as_view()生成一个view_func而后进行注册。

前面例子中的两次as_view生成两个视图函数。要生成一个,或许可以这样:

1
2
app.add_url_rule('/', view_func=MyView.as_view('myview'))
app.add_url_rule('/home', endpoint='myview')

as_view()的参数,必须传入一个name,如果有其他参数,会有View类的__init__()处理。

methods

可以使用methods属性来设置该视图类要处理的请求:

1
2
3
4
5
6
7
8
9
class MyView(View):
    methods = ["GET", "POST"]

    def dispatch_request(self):
        if request.method == "POST":
            return "Hello post"
        return "Hello get"

app.add_url_rule('/my-view', view_func=MyView.as_view('my-view'))

这等同于在add_url_rule中指定methods方法

MethodView

flask.views.MethodView是flask.views.View的派生类。对于定应REST API有用。

先把手册中的例子摆上,后面接触到REST后再回头看:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class CounterAPI(MethodView):
    def get(self):
        return str(session.get("counter", 0))

    def post(self):
        session["counter"] = session.get("counter", 0) + 1
        return redirect(url_for("counter"))

app.add_url_rule(
    "/counter", view_func=CounterAPI.as_view("counter")
)

Blueprint

对于flask项目,蓝图(Blueprint)可以实现各个模块的划分。

不用蓝图

不使用蓝图时,flask项目大致长下面这样:

1
2
3
4
myapp/
├── templates/
├── static/
└── app.py

但是如果有很多页面,这些页面有天然属于不同模块的话,应用文件app.py 可能长这样:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask
app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello World!'

# user
@app.route('/user/register')
def register():
    return 'register'

@app.route('/user/login')
def login():
    return 'login'

# admin
@app.route('/admin/users')
def listuser():
    return 'users'

@app.route('/admin/deluser')
def deluser():
    return 'deluser'

照这样下去,会很乱

使用Blueprint

蓝图方式,将代码按照功能模块进行划分

1
2
3
4
5
6
7
8
myapp/
├── admin/
│   ├── __init__.py
│   └── views.py
├── app.py
└── user/
    ├── __init__.py
    └── views.py

我们以admin为例,简单看看

创建蓝图

在admin目录下,我们需要一个__init__.py文件

1
2
3
4
5
from flask import Flask, Blueprint

admin_bp = Blueprint('admin', __name__, url_prefix='/admin')

from . import views

创建蓝图时,可以指定templates,static等资源的路径。

1
class flask.Blueprint(name, import_name, static_folder=None, static_url_path=None, template_folder=None, url_prefix=None, subdomain=None, url_defaults=None, root_path=None, cli_group=<object object>)

视图

再创建一个views.py文件(注意使用上面创建的蓝图 装饰器):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from admin import admin_bp

@admin_bp.route('/')
def home():
    return 'Hello admin'

@admin_bp.route('/users')
def listuser():
    return 'users'

@admin_bp.route('/deluser')
def deluser():
    return 'deluser'

注册蓝图

在主程序 app.py 中,对蓝图进行注册:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World!'

from admin import admin_bp

app.register_blueprint(admin_bp)

注册时,有其他参数可设置,比如 url_prefix='/admin'

有这三个文件,程序可以正常运行了...

杂项

创建蓝图时,指定静态文件夹(蓝图位于/admin,那么静态文件夹/admin/static):

1
admin = Blueprint('admin', __name__, static_folder='static')

要生成静态文件的url(注意 蓝图名.static),可以:

1
url_for('admin.static', filename='style.css')

模板路径也可 指定:

1
admin = Blueprint('admin', __name__, template_folder='templates')

蓝图组织方式

依据静态文件和模板文件的位置组织,蓝图有两种方式:

按蓝图分区

每个蓝图和它的资源在独立的目录下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
myapp/
├── app.py
├── static/
├── templates/
├── admin/
│   ├── __init__.py
│   ├── views.py
│   ├── static/
│   └── templates/
└── user/
    ├── __init__.py
    ├── views.py
    ├── static/
    └── templates/

按功能

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
myapp/
├── app.py
├── static/
│   ├── admin/
│   └── user/
├── templates/
│   ├── admin/
│   └── user/
└── view/
    ├── __init__.py
    ├── admin.py
    └── user.py

官方示例

作为参考,Flask官方给出的完整结构示例如下:

 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
/home/user/Projects/flask-tutorial
├── flaskr/
   ├── __init__.py
   ├── db.py
   ├── schema.sql
   ├── auth.py
   ├── blog.py
   ├── templates/
      ├── base.html
      ├── auth/
         ├── login.html
         └── register.html
      └── blog/
          ├── create.html
          ├── index.html
          └── update.html
   └── static/
       └── style.css
├── tests/
   ├── conftest.py
   ├── data.sql
   ├── test_factory.py
   ├── test_db.py
   ├── test_auth.py
   └── test_blog.py
├── .venv/
├── pyproject.toml
└── MANIFEST.in

参考

  • https://github.com/pallets/flask
  • https://flask.palletsprojects.com
  • https://flask.palletsprojects.com/en/3.0.x/tutorial/views/
  • https://flask.palletsprojects.com/en/3.0.x/views/
  • https://flask.palletsprojects.com/en/3.0.x/blueprints/
  • https://flask.palletsprojects.com/en/3.0.x/patterns/viewdecorators/
  • https://blog.ashutoshkrris.in/how-to-use-blueprints-to-organize-your-flask-apps
  • http://www.coolpython.net/flask_tutorial/basic/flask-blueprint.html