add_url_rule和app.route原理剖析

add_url_rule

  1. add_url_rule(rule,endpoint=None,view_func=None)

这个方法用来添加url与视图函数的映射。
如果没有填写endpoint,那么默认会使用view_func的名字作为endpoint,
有填写endpoint,使用endpoint指定的字符串作为view_func函数的别名。
在url_for调用时应使用endpoint传递的别名

  1. @app.route('/',endpoint='index')
  2. def hello_world():
  3. # return 'Hello World!' + url_for('my_list')
  4. return 'Hello World!'+url_for('alias')
  5.  
  6. def my_list():
  7. return '我是列表页'
  8.  
  9. app.add_url_rule('/list/',endpoint='alias',view_func=my_list)
  10.  
  11. # app.test_request_context
  12. # 请求上下文
  13. with app.test_request_context():
  14. print(url_for('index')) #结果是:/
  15.  
  16. if __name__ == '__main__':
  17. app.run(debug=True)

add_url_rule相当于把/list/和my_list关联起来。endpioint相等于给视图函数命名一个别名。

  1. def my_list():
  2. return '我是列表页'
  3. app.add_url_rule('/list/',endpoint='alias',view_func=my_list)
  4. #和下面的等价:
  5. @app.route('/list/',endpoint='alias')
  6. def my_list():
  7. return '我是列表页'

app.route原理

@app.route('/')装饰器底层是使用add_url_rule来实现url与视图函数映射的,

标准类视图及其使用场景

标准视图继承自flask.views.View,并且在子类中必须实现dispatch_request方法,这个方法类似于视图函数,也要返回一个基于Response或者其子类的对象。

  1. 标准类视图,必须继承自flask.views.View.
  2. 必须实现dipatch_request方法,当请求过来后会执行该方法且方法的返回值和之前的函数视图返回值一样,必须返回Response或者子类的对象,或者是字符串,或者是元组。
  3. 必须通过app.add_url_rule(rule,endpoint,view_func)来做url与视图的映射。view_func这个参数,需要使用类视图下的as_view类方法类转换:ListView.as_view('list')。
  4. 如果指定了endpoint,那么在使用url_for反转的时候就必须使用endpoint指定的别名。如果没有指定endpoint,那么就可以使用as_view(视图名字)中指定的视图名字来作为反转。
  5. 类视图有以下好处:可以继承,把一些共性的东西抽取出来放到父视图中,子视图直接拿来用。但是也不是说所有的视图都要使用类视图,这个要根据情况而定。
  1. # 有几个url需要返回json数据
  2. # 有几个视图,是需要返回相同的变量
  3.  
  4. class JSONView(views.View):
  5. def get_data(self):
  6. raise NotImplementedError
  7.  
  8. def dispatch_request(self):
  9. return jsonify(self.get_data())
  10.  
  11. class ListView(JSONView):
  12. def get_data(self):
  13. return {"username":'wqbin','password':''}
  14.  
  15. app.add_url_rule('/list/',endpoint='my_list',view_func=ListView.as_view("list"))

  1. class ADSView(views.View):
  2. def __init__(self):
  3. super(ADSView, self).__init__()
  4. self.context = {
  5. 'ads': '这里是wqbin的博客'
  6. }
  7.  
  8. class LoginView(ADSView):
  9. def dispatch_request(self):
  10. self.context.update({
  11. 'username': 'wqbin'
  12. })
  13. return render_template('login.html',**self.context)
  14.  
  15. class RegistView(ADSView):
  16. def dispatch_request(self):
  17. return render_template('regist.html',**self.context)
  18.  
  19. app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
  20. app.add_url_rule('/regist/',view_func=RegistView.as_view('regist'))

基于调度方法的类视图

基于请求方法的类视图:
基于方法的类视图,是根据请求的method来执行不同的方法的。

如果用户是发送的get请求,那么将会执行这个类的get方法。如果用户发送的是post请求,那么将会执行这个类的post方法。其他的method类似,比如delete、put。
这种方式,可以让代码更加简洁。
所有和get请求相关的代码都放在get方法中,所有和post请求相关的代码都放在post方法中。就不需要跟之前的函数一样,通过request.method == 'GET'。

  1. class LoginView(views.MethodView):
  2. def __render(self,error=None):
  3. return render_template('login.html',error=error)
  4.  
  5. def get(self):
  6. return self.__render()
  7.  
  8. def post(self):
  9. username = request.form.get('username')
  10. password = request.form.get('password')
  11. if username == 'wqbin' and password == '':
  12. return '登录成功'
  13. else:
  14. return self.__render(error='用户名或密码错误')
  15.  
  16. app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <form action="" method="post">
  9. <table>
  10. <tbody>
  11. <tr>
  12. <td>用户名:</td>
  13. <td><input type="text" name="username"></td>
  14. </tr>
  15. <tr>
  16. <td>密码:</td>
  17. <td><input type="password" name="password"></td>
  18. </tr>
  19. <tr>
  20. <td></td>
  21. <td><input type="submit" value="立即登录"></td>
  22. </tr>
  23. </tbody>
  24. </table>
  25. {% if error %}
  26. <p style="color: red;">{{ error }}</p>
  27. {% endif %}
  28. </form>
  29. </body>
  30. </html>

html

类视图中使用装饰器

  1. 如果使用的是函数视图,那么自定义的装饰器必须放在`app.route`下面
  2. 类视图的装饰器,需要重写类视图的一个类属性`decorators`,这个类属性是一个列表或者元组都可以,里面装的就是所有的装饰器。
  1. def login_required(func):
  2. @wraps(func)
  3. def wrapper(*args,**kwargs):
  4. username = request.args.get('username')
  5. if username and username == 'wqbin':
  6. return func(*args,**kwargs)
  7. else:
  8. return '请先登录'
  9. return wrapper
  10.  
  11. @app.route('/settings/')
  12. @login_required
  13. def settings():
  14. return '这是设置界面'
  15.  
  16. class ProfileView(views.View):
  17. decorators = [login_required]
  18. def dispatch_request(self):
  19. return '这是个人中心界面'
  20.  
  21. app.add_url_rule('/profile/',view_func=ProfileView.as_view('profile'))

蓝图的基本使用

1. 蓝图的作用

让我们的Flask项目更加模块化,结构更加清晰。
    可以将相同模块的视图函数放在同一个蓝图下,同一个文件中,方便管理。

2. 基本语法:

* 在蓝图文件中导入Blueprint:

  1. from flask import Blueprint
  2. user_bp = Blueprint('user',__name__)

  我们仔细了解Blueprint类的构造函数:

  1. def __init__(self, name, import_name, static_folder=None,
  2. static_url_path=None, template_folder=None,
  3. url_prefix=None, subdomain=None, url_defaults=None,
  4. root_path=None):
  5. _PackageBoundObject.__init__(self, import_name, template_folder,
  6. root_path=root_path)
  7. self.name = name
  8. self.url_prefix = url_prefix
  9. self.subdomain = subdomain
  10. self.static_folder = static_folder
  11. self.static_url_path = static_url_path
  12. self.deferred_functions = []
  13. if url_defaults is None:
  14. url_defaults = {}
  15. self.url_values_defaults = url_defau

__init__.py

* 在主app文件中注册蓝图:

  1. from blueprints.user import user_bp
  2. app.regist_blueprint(user_bp)

3. 如果想要某个蓝图下的所有url都有一个url前缀,那么可以在定义蓝图的时候,指定url_prefix参数:

  1. user_bp = Blueprint('user',__name__,url_prefix='/user/')

在定义url_prefix的时候,要注意后面的斜杠,如果给了,那么以后在定义url与视图函数的时候,就不要再在url前面加斜杠了。

4. 蓝图模版文件的查找:

* 如果项目中的templates文件夹中有相应的模版文件,就直接使用了。
* 如果项目中的templates文件夹中没有相应的模版文件,那么就到在定义蓝图的时候指定的路径中寻找。并且蓝图中指定的路径可以为相对路径,相对的是当前这个蓝图文件所在的目录。比如:

  1. news_bp = Blueprint('news',__name__,url_prefix='/news',template_folder='bp_template')

因为这个蓝图文件是在blueprints/news.py,那么就会到blueprints这个文件夹下的bp_template文件夹中寻找模版文件。

5. 蓝图中静态文件的查找规则:

* 在模版文件中,加载静态文件,如果使用url_for('static'),那么就只会在app指定的静态文件夹目录下查找静态文件。
* 如果在加载静态文件的时候,指定的蓝图的名字,比如`news.static`,那么就会到这个蓝图指定的static_folder下查找静态文件。

  1. <link rel="stylesheet" href="{{ url_for('static',filename='news_list.css') }}">
  2. <link rel="stylesheet" href="{{ url_for('newsbp.static',filename='news_list.css') }}">

6. url_for反转蓝图中的视图函数为url:

* 如果使用蓝图,那么以后想要使用url_for反转蓝图中的视图函数为url,那么就应该在使用url_for的时候指定这个蓝图,比如`newsbp.news_list`。否则就找不到这个endpoint。在模版中的url_for同样也是要满足这个条件,就是指定蓝图的名字。

* 即使在同一个蓝图中反转视图函数,也要指定蓝图的名字。

  1. @app.route('/')
  2. def hello_world():
  3. print(url_for('newsbp.news_list'))
  4. return render_template('index.html')

子域名实现详解

蓝图实现子域名:
1. 使用蓝图技术。
2. 在创建蓝图对象的时候,需要传递一个subdomain参数,来指定这个子域名的前缀。例如:cms_bp = Blueprint('cmsbp',__name__,subdomain='cms')。

  1. from flask import Blueprint
  2.  
  3. cms_bp = Blueprint('cmsbp',__name__,subdomain='cms')
  4.  
  5. @cms_bp.route('/')
  6. def index():
  7. return 'cms index page'

3. 需要在主app文件中,需要配置app.config的SERVER_NAME参数。例如:

  1. app.config['SERVER_NAME'] = 'jd.com:5000'
  • ip地址不能有子域名。
  • localhost也不能有子域名。

4. 在C:\Windows\System32\drivers\etc下,找到hosts文件,然后添加域名与本机的映射。例如:

127.0.0.1 jd.com
127.0.0.1 cms.jd.com

域名和子域名都需要做映射。

第五章 Flask视图高级的更多相关文章

  1. mariadb(第五章)视图、事物、索引、外键

    视图 对于复杂的查询,在多个地方被使用,如果需求发生了改变,需要更改sql语句,则需要在多个地方进行修改,维护起来非常麻烦 假如因为某种需求,需要将user拆房表usera和表userb,该两张表的结 ...

  2. 第五章:深入Python的dict和set

    第五章:深入Python的dict和set 课程:Python3高级核心技术 5.1 dict的abc继承关系 class Mapping(Collection): __slots__ = () &q ...

  3. 读JS高级——第五章-引用类型 _记录

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 第五章 MySQL事务,视图,索引,备份和恢复

    第五章 MySQL事务,视图,索引,备份和恢复 一.事务 1.什么是事务 事务是一种机制,一个操作序列,它包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求.要么都执行 ...

  5. 【Flask】视图高级

    # 视图高级笔记:### `add_url_rule(rule,endpoint=None,view_func=None)`这个方法用来添加url与视图函数的映射.如果没有填写`endpoint`,那 ...

  6. flask之三:视图高级

    视图高级 app.route和app.add_url_rule app.add_url_rule app.add_url_rule('/list/',endpoint='myweb',view_fun ...

  7. C#高级编程 (第六版) 学习 第五章:数组

    第五章 数组 1,简单数组 声明:int[] myArray; 初始化:myArray = new int[4]; 为数组分配内存. 还可以用如下的方法: int[] myArray = new in ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (22) -----第五章 加载实体和导航属性之延迟加载

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第五章 加载实体和导航属性 实体框架提供了非常棒的建模环境,它允许开发人员可视化地使 ...

  9. 精通Web Analytics 2.0 (7) 第五章:荣耀之钥:度量成功

    精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第五章:荣耀之钥:度量成功 我们的分析师常常得不到我们应得的喜欢,尊重和资金,因为我们没有充分地衡量一个黄金概念:成果.因为我们 ...

随机推荐

  1. Linux IO的五种模型 ongoing

    服务器端编程经常需要构造高性能的IO模型,常见的IO模型: 阻塞I/O模型  (Blocking IO) ------------(同步)(阻塞) 非阻塞I/O模型 (Non-Blocking IO) ...

  2. C语言--函数嵌套调用

    一.实验作业(6分) 本周作业要求: 选一题PTA题目介绍. 学习工程文件应用,设计实现学生成绩管理系统. 学生成绩管理系统要求 设计一个菜单驱动的学生成绩管理程序,管理n个学生m门考试科目成绩,实现 ...

  3. Python之装饰器笔记

    概述: 用于管理和增强函数和类行为的代码 提供一种在函数或类定义中插入自动运行代码的机制 特点  更明确的语法.更高的代码可维护性.更好的一致性 编写 函数基础: 将函数赋给变量.将函数作为参数传递. ...

  4. Struts2连接Mysql的Crud使用

    今天分享的是struts2框架中增删改查的用法: 一:利用Struts2框架 1.1在pom.xml中导入相关依赖 <project xmlns="http://maven.apach ...

  5. [Vue]导航守卫:全局的、单个路由独享的、组件级的

    正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航.有多种机会植入路由导航过程中:全局的, 单个路由独享的, 或者组件级的. 记住参数或查询的改变并不会触发进入/离开的 ...

  6. springboot启动流程(五)创建ApplicationContext

    所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 正文 springboot在启动过程中将会根据当前应用的类型创建对应的ApplicationC ...

  7. php定界符介绍

    php界定符就是为了照样输出内容.它的格式如下: <<<EOF ...... EOF; 其中EOF是自定义的变量,但要成对出现! 首先附上一段php代码: <?php $a = ...

  8. Vue路由参数

    vue路由参数 1.参数router-link vue.prototype.xxx = {add:fn}`所有组件中,使用this.xxx就能拿到这个对象2.查询字符串 (1)配置: :to=&quo ...

  9. AngularJS入门教程之与服务器(Ajax)交互操作示例

    AngularJS从Web服务器请求资源都是通过Ajax来完成,所有的操作封装在$http服务中,$http服务是只能接收一个参数的函数,这个参数是一个对象,用来完成HTTP请求的一些配置,函数返回一 ...

  10. python日志实时分析

    python随着人工智能的发展,越来越火热.但其实python在运维测试方面,也是一把利器. 最近就碰到了个需求,就顺手写了个python程序.用惯了go,不过发现python好像更简单点 :-) 涉 ...