add_url_rule和app.route原理剖析

add_url_rule

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

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

@app.route('/',endpoint='index')
def hello_world():
# return 'Hello World!' + url_for('my_list')
return 'Hello World!'+url_for('alias') def my_list():
return '我是列表页' app.add_url_rule('/list/',endpoint='alias',view_func=my_list) # app.test_request_context
# 请求上下文
with app.test_request_context():
print(url_for('index')) #结果是:/ if __name__ == '__main__':
app.run(debug=True)

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

def my_list():
return '我是列表页'
app.add_url_rule('/list/',endpoint='alias',view_func=my_list)
#和下面的等价:
@app.route('/list/',endpoint='alias')
def my_list():
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. 类视图有以下好处:可以继承,把一些共性的东西抽取出来放到父视图中,子视图直接拿来用。但是也不是说所有的视图都要使用类视图,这个要根据情况而定。
# 有几个url需要返回json数据
# 有几个视图,是需要返回相同的变量 class JSONView(views.View):
def get_data(self):
raise NotImplementedError def dispatch_request(self):
return jsonify(self.get_data()) class ListView(JSONView):
def get_data(self):
return {"username":'wqbin','password':''} app.add_url_rule('/list/',endpoint='my_list',view_func=ListView.as_view("list"))

class ADSView(views.View):
def __init__(self):
super(ADSView, self).__init__()
self.context = {
'ads': '这里是wqbin的博客'
} class LoginView(ADSView):
def dispatch_request(self):
self.context.update({
'username': 'wqbin'
})
return render_template('login.html',**self.context) class RegistView(ADSView):
def dispatch_request(self):
return render_template('regist.html',**self.context) app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
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'。

class LoginView(views.MethodView):
def __render(self,error=None):
return render_template('login.html',error=error) def get(self):
return self.__render() def post(self):
username = request.form.get('username')
password = request.form.get('password')
if username == 'wqbin' and password == '':
return '登录成功'
else:
return self.__render(error='用户名或密码错误') app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
<table>
<tbody>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="立即登录"></td>
</tr>
</tbody>
</table>
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
</form>
</body>
</html>

html

类视图中使用装饰器

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

蓝图的基本使用

1. 蓝图的作用

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

2. 基本语法:

* 在蓝图文件中导入Blueprint:

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

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

def __init__(self, name, import_name, static_folder=None,
static_url_path=None, template_folder=None,
url_prefix=None, subdomain=None, url_defaults=None,
root_path=None):
_PackageBoundObject.__init__(self, import_name, template_folder,
root_path=root_path)
self.name = name
self.url_prefix = url_prefix
self.subdomain = subdomain
self.static_folder = static_folder
self.static_url_path = static_url_path
self.deferred_functions = []
if url_defaults is None:
url_defaults = {}
self.url_values_defaults = url_defau

__init__.py

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

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

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

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

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

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

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

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下查找静态文件。

    <link rel="stylesheet" href="{{ url_for('static',filename='news_list.css') }}">
<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同样也是要满足这个条件,就是指定蓝图的名字。

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

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

子域名实现详解

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

from flask import Blueprint

cms_bp = Blueprint('cmsbp',__name__,subdomain='cms')

@cms_bp.route('/')
def index():
return 'cms index page'

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

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. 20175316 盛茂淞 2018-2019-2 《Java程序设计》实验五 《网络安全与编程》 实验报告

    20175316 盛茂淞 2018-2019-2 <Java程序设计>实验五 <网络安全与编程> 实验报告 一.实验报告封面 课程:Java程序设计 班级:1753班 姓名:盛 ...

  2. python3 爬虫利用Requests 实现下载进度条

    一.编写代码 from datetime import datetime,date,timedelta from contextlib import closing import urllib,url ...

  3. Java与计算机常识

    DB2   IBM公司的数据库 Oracle  Orcle的数据库 Mysql    数据库(免费) 1.  jetty    小型服务器(类似于tomcat) Jetty 是一个开源的servlet ...

  4. 并不对劲的THUWC2020

    day -inf 因为一些(不是寒假时长锐减的)小原因,今年(2020)THUWC在去年(2019)就举办了! 这导致某个小弱智只能临阵磨枪了QAQ- day 1 早: 没有看到吕爷,签到.试机. 签 ...

  5. 谈jdbcTemplate与mybatis

    为什么会产生 Hibernate Mybatis 这类的dao层框架 传统的jdbc 虽然执行速度很快,但是开发效率很低,随着面向对象开发的设计思想,在面向对象编程中 将对象 进行持久化,存入关系型的 ...

  6. (四)CXF之处理Map类型的数据

    一.需求描述 正常来讲webService可以处理Java 数据类型.JavaBean.List等,但是却不能处理Map数据类型.本章讲解如何使用适配器来使得web服务可以处理Map数据类型. 流程: ...

  7. C#特性 详解

    一:Conditional:条件特性,预定义了一个条件方法. 使用方法: [Conditional("DEBUG")] public void test() { MessageBo ...

  8. cmd查找端口占用情况

    查找端口占用情况:netstat -ano|findstr 4848 查看使用指定端口的应用程序:tasklist|findstr xxxx,xxxx指的是pid 结束指定进程:taskkill /p ...

  9. adminMongo:mongoDB node GUI(mongoDB图形化界面)

    adminMongo:mongoDB node GUI(mongoDB图形化界面) 获取项目项目 克隆:git clone https://github.com/mrvautin/adminMongo ...

  10. StringBuilder 去除最后一个多余的字符的方法

    public class StringBuilterTest { public static void main(String[] args) { //新增一个map Map<String, S ...