未命名作品.jpg


1 视图函数

之前我们已经了解过了视图函数的大概用法,本节深入了解一下视图函数

1.1 endpoint简介

endpint参数是写在注册路由的装饰器中的一个参数,学名叫端点,我们可以理解为函数的别名。原来我们翻转视图函数的url的时候是直接通过是如函数的名字,如url_for('函数名'),现在我们可以指定一个endpoint='fbv'参数来进行翻转url。如果不指定endpoint,默认就以函数名作为端点名。
实例:

  1. @app.route('/fbvtest/',methods=['GET','POST'],endpoint='fbv')
  2. def fbvtest():
  3. url_demo = url_for('fbv')
  4. return '利用视图函数别名翻转的url为:{}'.format(url_demo)

03-02 视图函数和视图类 - 图2
关键词:

利用@app.route() 的endpoint=’fbv’参数可以自由指定端点名,url_for可以根据指定的端点名进行翻转。
1.2 装饰器注册路由源码浅析

(1) 首先写一个小视图函数

  1. #注册装饰器的原理
  2. #1 v = app.route('/source_code_demo/',endpoint='source_code')
  3. #2 v(source_code_demo)
  4. @app.route('/source_code_demo/',endpoint='source_code')
  5. def source_code_demo():
  6. return 'source_code_demo'

(2) 查看app.route()源码

  1. ...
  2. def route(self, rule, **options):
  3. ...
  4. def decorator(f):
  5. endpoint = options.pop('endpoint', None)
  6. self.add_url_rule(rule, endpoint, f, **options)
  7. return f
  8. return decorator

解析:

  • ,发现route()返回的是decorator函数地址,然后基于语法糖和装饰器的原理,decorator会加括号运行,像这样decorator(source_code_demo)
  • decorator函数中首先取出endpoint,然后运行self.add_url_rule(rule, endpoint, f, **options)
  • 所以 self.add_url_rule(rule, endpoint, f, **options)就是注册路由的核心

(3) 点进self.add_url_rule(rule, endpoint, f, **options)查看源码,
再点进_endpoint_from_view_func(view_func)查看源码

  1. ...
  2. @setupmethod
  3. def add_url_rule(self, rule, endpoint=None, view_func=None,
  4. provide_automatic_options=None, **options):
  5. ...
  6. if endpoint is None:
  7. endpoint = _endpoint_from_view_func(view_func)
  8. options['endpoint'] = endpoint
  9. methods = options.pop('methods', None)
  10. # if the methods are not given and the view_func object knows its
  11. # methods we can use that instead. If neither exists, we go with
  12. # a tuple of only ``GET`` as default.
  13. if methods is None:
  14. methods = getattr(view_func, 'methods', None) or ('GET',)
  15. ...
  1. def _endpoint_from_view_func(view_func):
  2. """Internal helper that returns the default endpoint for a given
  3. function. This always is the function name.
  4. """
  5. assert view_func is not None, 'expected view func if endpoint ' \
  6. 'is not provided.'
  7. return view_func.__name__

解析:

  • 由上述代码我们可以直到如果没有指定endpoint,我们调用了 _endpoint_from_view_func()
  • 观察_endpoint_from_view_func函数我们可以知道,返回了视图函数的名字给了endpoint赋值
  • methos没有指定会给methos赋默认值('GET',)

小结:

  1. self.add_url_rule(rule, endpoint, f, options)就是注册路由的核心
  2. 观察_endpoint_from_view_func函数我们可以知道,返回了视图函数的名字给了endpoint赋值
  3. methos没有指定会给methods赋默认值('GET',)

03-02 视图函数和视图类 - 图3

1.3 另一种注册路由的方式—-app.add_url_rule()

通过看上一个小节写的源码,现在我们知道了app.route() 的核心就是self.add_url_rule(rule, endpoint, f, options)就是注册路由的核心。所以我们可以直接使用app.add_url_rule()的方式来注册路由。
实例:

  1. def add_url_test():
  2. return '实现了add_url方式注册路由'
  3. # url 端点 函数地址
  4. app.add_url_rule('/add_url_test/',endpoint='add_demo',view_func=add_url_test)

image.png

1.4 视图函数中添加自定义装饰器

我们在平时的开发的过程中,很多需要权限验证的功能需要用到装饰器,下面的代码是如何在flask中实现一个装饰器。

  1. from flask import Flask, request
  2. from functools import wraps
  3. app = Flask(__name__)
  4. def login_verify(func):
  5. @wraps(func)
  6. def wrapper(*args, **kwargs):
  7. user_name = request.args.get('user')
  8. password = request.args.get('password')
  9. if user_name == 'mark' and password == '123':
  10. return func(*args,**kwargs)
  11. else:
  12. return '请登录'
  13. return wrapper
  14. @app.route('/')
  15. def hello_world():
  16. return 'Hello World!'
  17. @app.route('/my_info/')
  18. @login_verify
  19. def my_info():
  20. return '个人信息页面'

关键词

  1. 装饰器一定要写在注册路由的下面,写在视图函数的上面。
  2. 装饰器内部一定要使用@wraps(func)方法,用于保护被装饰函数的属性。

    2 视图类

    2.1 视图类的基本写法

    ```python from flask import Flask, views, request, url_for from functools import wraps

def login_verify(func): @wraps(func) def wrapper(args, **kwargs): user_name = request.args.get(‘user’) password = request.args.get(‘password’) if user_name == ‘mark’ and password == ‘123’: return func(args,**kwargs) else: return ‘请登录’ return wrapper

class CBVTest(views.MethodView):

  1. methods = ['GET','POST'] # 指定可以接收的方法有什么
  2. decorators = [login_verify,] # 指定自定义的装饰器
  3. def get(self):
  4. print(url_for('cbvtest'))
  5. return 'cbv_get'
  6. def post(self):
  7. return 'cbv_post'

app.add_url_rule(‘/cbvtest’,view_func=CBVTest.as_view(name=’cbvtest’),endpoint=’end_demo’)

  1. 讲解:
  2. 1. 首先从flask中导入 `views`<br />
  3. 1. 写一个类一定要继承 `views.MethodView`<br />
  4. 1. 在类中写`methods = ['GET','POST']` 可以指定可接受的请求类型<br />
  5. 1. 在类中写`decorators = [login_verify,]`可以指定装饰器,第一个装饰器是最里层函数依次往后包裹<br />
  6. 1. 在类中写`def get(self):`用于获取get请求<br />
  7. 1. 在类中写`def post(self):`用于获取post请求<br />
  8. 1. 添加路由的方法使用<br />
  9. ```python
  10. app.add_url_rule(
  11. '路由',view_func=CBVTest.as_view(name='自定义一个端点名字'))

其原理是CBVTest.as_view(name='自定义一个端点名字')会返回一个函数,name是为这个函数命的名字,可以通过这个函数进行分发请求等操作。

3 详细讲解注册路由的参数:

常用的参数

  1. @app.routeapp.add_url_rule参数:
  2. rule, URL规则
  3. view_func, 视图函数名称
  4. endpoint = None, 名称,用于反向生成URL,即: url_for('名称')
  5. methods = None, 允许的请求方式,如:["GET", "POST"]

不常用的参数(了解)

(1) 对URL最后的 / 符号是否严格要求 strict_slashes = False

  1. strict_slashes = False
  2. '''
  3. @app.route('/index', strict_slashes=False)
  4. #访问http://www.xx.com/index/ 或http://www.xx.com/index均可
  5. @app.route('/index', strict_slashes=True)
  6. #仅访问http://www.xx.com/index
  7. '''

(2) 重定向到指定地址redirect_to=“ ”

  1. @app.route("/",redirect_to='/home/')
  2. def index():
  3. return '根路径'
  4. @app.route("/home/")
  5. def admin_demo():
  6. return 'home路径'

(3) 为函数提供默认参数值

  1. defaults = None, 默认值, URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}

(4)子域名设置subdomain=“ ”

  1. from flask import Flask,url_for
  2. app = Flask(__name__)
  3. app.debug = True
  4. '''
  5. 先在hosts设置域名解析(就是在本机的hosts文件上编辑上域名对应ip的关系)
  6. 域名解析会先解析本地如果没有再解析dns服务器
  7. C:\Windows\System32\drivers\etc\hosts
  8. 127.0.0.1 mark.com
  9. 127.0.0.1 admin.mark.com
  10. '''
  11. app.config['SERVER_NAME'] = 'mark.com:5000' # 这个代表访问这个域名的时候要访问5000端口
  12. @app.route("/")
  13. def index():
  14. return '设置域名成功'
  15. @app.route("/admin_demo/",subdomain='admin')
  16. def admin_demo():
  17. return '设置子域名成功'
  18. '''
  19. 在浏览器中访问主域名
  20. mark.com:5000/
  21. 在浏览器中访问子域名
  22. admin.mark.com:5000/admin_demo/
  23. 注意:后面跟的path路径部分正常写
  24. '''
  25. if __name__ == '__main__':
  26. app.run(host='127.0.0.1',port=5000) # 测试服务器不稳定,尽量手动制定ip和端口

03-02 视图函数和视图类 - 图5
03-02 视图函数和视图类 - 图6