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. [转帖]详解shell脚本括号区别--$()、$「 」、$「 」 、$(()) 、「 」 、「[ 」]

    详解shell脚本括号区别--$().$「 」.$「 」 .$(()) .「 」 .「[ 」] 原创 波波说运维 2019-07-31 00:01:00 https://www.toutiao.com ...

  2. 方法重载,new,override

    方法重载:参数列表不一样,方法名字一样,包括泛型,和返回值无关 new: 复写,方法重载   overload  继承是对于普通方法和属性  复写 父类的 override:覆盖,重写 ,  对于抽象 ...

  3. springboot用controller跳转html页面

    之前SSM框架,里面有webapps文件夹,用来存放前端页面和各种前端资源,现在SpringBoot中没有webapps文件夹,springboot结构如下: 第一.resourses下文件夹publ ...

  4. Navicat连接Oracle数据库用户权限问题

    解决Navicat连接Oracle数据库用户权限问题: 第一步:在cmd窗口运行[sqlplus], 第二步:输入Oracle的用户名和口令连接Oracle数据库, 第三步:执行授权代码,给用户授予D ...

  5. js实现放烟花效果——点击处会从下向上升起烟花

    一个box中,点击其中的任意位置,会有烟花从正下方升起到点击处,并燃放出一圈圆形的烟花.代码如下: 首先是布局以及样式: <style> .box{ width: 1100px; heig ...

  6. ubuntu中不能使用终端的情况

    跟着网上的步骤去升级了一波python3,可谓一波未平! 当我将ubuntu中自带的python3.5升级3.6时,突然发现一个问题,怎么终端打不开了,于是去百度,找到一个博主的笔记,和我的情况一模一 ...

  7. Django之Form与ModelForm组件

    Django之Form与ModelForm组件 1.Form介绍 Form组件的主要功能如下: 生成页面可用的HTML标签 对用户提交的数据进行校验 O 保留上次的输入内容 普通方式手写注册功能 vi ...

  8. C#基础算法题 找出最大值和最小值

    找出最大值和最小值 题目要求 输入n个数,n<=100,找到其中最小的数和最大的数 实现代码 using System; namespace _1.求最大最小 { class Program { ...

  9. 【判环】Perpetuum Mobile

    Perpetuum Mobile 题目描述 The year is 1902. Albert Einstein is working in the patent office in Bern. Many ...

  10. 2019杭电多校二 L. Longest Subarray (线段树)

    大意: 给定序列$a$, 元素范围$[1,C]$, 求一个最长子序列, 满足每个元素要么不出现, 要么出现次数$\le K$. 枚举右端点, 考虑左端点合法的位置. 显然一定是$C$种颜色合法位置的交 ...