Flask视图函数高级
1.1 add_url_rule的用法
add_url_rule(rule,endpoint=None,view_func=None)
这个方法用来添加url与视图函数的映射。如果没有填写endpoint
,那么默认会使用view_func
的名字作为endpoint
。以后在使用url_for
的时候,就要看在映射的时候有没有传递endpoint
参数,如果传递了,那么就应该使用endpoint
指定的字符串,如果没有传递,那么就应该使用view_func
的名字。
- flask代码
from flask import Flask,url_for
app = Flask(__name__)
@app.route('/',endpoint='index')
def hello_world():
print(url_for('python'))
return 'Hello World!'
def my_list():
return '我是列表页'
app.add_url_rule('/list/',endpoint='python',view_func=my_list)
# app.test_request_context
# 请求上下文
with app.test_request_context():
print(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
1.2 app.route装饰器的用法
app.route(rule,**options)
装饰器: 这个装饰器底层,其实也是使用add_url_rule
来实现url与视图函数映射的。
from flask import Flask,url_for
app = Flask(__name__)
@app.route('/',endpoint='index')
def hello_world():
print(url_for('python'))
return 'Hello World!'
# app.test_request_context
# 请求上下文
with app.test_request_context():
print(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
1.3 类视图
1.3.1 标准类视图
- 标准类视图,必须继承自
flask.views.View
. - 必须实现
dipatch_request
方法,以后请求过来后,都会执行这个方法。这个方法的返回值就相当于是之前的函数视图一样。也必须返回Response
或者子类的对象,或者是字符串,或者是元组。 - 必须通过
app.add_url_rule(rule,endpoint,view_func)
来做url与视图的映射。view_func
这个参数,需要使用类视图下的as_view
类方法类转换:ListView.as_view('list')
。 - 如果指定了
endpoint
,那么在使用url_for
反转的时候就必须使用endpoint
指定的那个值。如果没有指定endpoint
,那么就可以使用as_view(视图名字)
中指定的视图名字来作为反转。 - 类视图有以下好处:可以继承,把一些共性的东西抽取出来放到父视图中,子视图直接拿来用就可以了。但是也不是说所有的视图都要使用类视图,这个要根据情况而定。
flask
代码:
from flask import Flask,views,url_for,jsonify,render_template
app = Flask(__name__)
# 有几个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":'xiaoming','password':'111111'}
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': '今年过节不收礼'
}
class LoginView(ADSView):
def dispatch_request(self):
self.context.update({
'username': 'xiaoming'
})
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'))
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
login.html
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是登录页面
<p>{{ ads }}</p>
</body>
</html>
regist.html
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
这是注册页面
<p>{{ ads }}</p>
</body>
</html>
1.3.2 基于请求方法的类视图
- 基于方法的类视图,是根据请求的
method
来执行不同的方法的。如果用户是发送的get
请求,那么将会执行这个类的get
方法。如果用户发送的是post
请求,那么将会执行这个类的post
方法。其他的method类似,比如delete
、put
。 - 这种方式,可以让代码更加简洁。所有和
get
请求相关的代码都放在get
方法中,所有和post
请求相关的代码都放在post
方法中。就不需要跟之前的函数一样,通过request.method == 'GET'
。
flask
代码:
from flask import Flask,views,render_template,request
app = Flask(__name__)
@app.route('/')
def hello_world():
if request.method == 'GET':
return 'Hello World!'
else:
# 写一些post请求的代码
pass
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 == 'zhiliao' and password == '111111':
return '登录成功'
else:
return self.__render(error='用户名或密码错误')
app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
if __name__ == '__main__':
app.run(debug=True)
index.html
代码:
<!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>
1.3.3 类视图中的装饰器
- 如果使用的是函数视图,那么自己定义的装饰器必须放在
app.route
下面。否则这个装饰器就起不到任何作用。 - 类视图的装饰器,需要重写类视图的一个类属性
decorators
,这个类属性是一个列表或者元组都可以,里面装的就是所有的装饰器。
flask
代码:
from flask import Flask,request,views
from functools import wraps
app = Flask(__name__)
def login_required(func):
@wraps(func)
def wrapper(*args,**kwargs):
# /settings/?username=xxx
username = request.args.get('username')
if username and username == 'zhiliao':
return func(*args,**kwargs)
else:
return '请先登录'
return wrapper
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/settings/')
@login_required
def settings():
return '这是设置界面'
# login_required(app.route('/settings/')(settings))
#
# app.route('/settings/')(login_required(settings))
class ProfileView(views.View):
decorators = [login_required]
def dispatch_request(self):
return '这是个人中心界面'
app.add_url_rule('/profile/',view_func=ProfileView.as_view('profile'))
if __name__ == '__main__':
app.run(debug=True)
1.4 蓝图
1.4.1 蓝图的使用
蓝图的作用就是让我们的
Flask
项目更加模块化,结构更加清晰。可以将相同模块的视图函数放在同一个蓝图下,同一个文件中,方便管理。-
基本语法:
- 在蓝图文件中导入
Blueprint
:from flask import Blueprint user_bp = Blueprint('user',__name__)
- 在主
app
文件中注册蓝图:from blueprints.user import user_bp app.regist_blueprint(user_bp)
- 在蓝图文件中导入
-
如果想要某个蓝图下的所有
url
都有一个url
前缀,那么可以在定义蓝图的时候,指定url_prefix
参数:user_bp = Blueprint('user',__name__,url_prefix='/user/')
在定义
url_prefix
的时候,要注意后面的斜杠,如果给了,那么以后在定义url
与视图函数的时候,就不要再在url
前面加斜杠了。 -
蓝图模版文件的查找:
- 如果项目中的
templates
文件夹中有相应的模版文件,就直接使用了。 - 如果项目中的
templates
文件夹中没有相应的模版文件,那么就到在定义蓝图的时候指定的路径中寻找。并且蓝图中指定的路径可以为相对路径,相对的是当前这个蓝图文件所在的目录。比如:
因为这个蓝图文件是在news_bp = Blueprint('news',__name__,url_prefix='/news',template_folder='muban')
blueprints/news.py
,那么就会到blueprints
这个文件夹下的muban
文件夹中寻找模版文件。
- 如果项目中的
-
蓝图中静态文件的查找规则:
- 在模版文件中,加载静态文件,如果使用
url_for('static')
,那么就只会在app
指定的静态文件夹目录下查找静态文件。 - 如果在加载静态文件的时候,指定的蓝图的名字,比如
news.static
,那么就会到这个蓝图指定的static_folder
下查找静态文件。
- 在模版文件中,加载静态文件,如果使用
-
url_for
反转蓝图中的视图函数为url
:- 如果使用蓝图,那么以后想要反转蓝图中的视图函数为
url
,那么就应该在使用url_for
的时候指定这个蓝图。比如news.news_list
。否则就找不到这个endpoint
。在模版中的url_for
同样也是要满足这个条件,就是指定蓝图的名字。 - 即使在同一个蓝图中反转视图函数,也要指定蓝图的名字。
- 如果使用蓝图,那么以后想要反转蓝图中的视图函数为
1.4.2 蓝图实现子域名
- 使用蓝图技术。
- 在创建蓝图对象的时候,需要传递一个
subdomain
参数,来指定这个子域名的前缀。例如:cms_bp = Blueprint('cms',__name__,subdomain='cms')
。 - 需要在主app文件中,需要配置app.config的SERVER_NAME参数。例如:
app.config['SERVER_NAME'] = 'jd.com:5000'
-
ip
地址不能有子域名。 -
localhost
也不能有子域名。
-
- 在
C:\Windows\System32\drivers\etc
下,找到hosts文件,然后添加域名与本机的映射。例如:
域名和子域名都需要做映射。127.0.0.1 jd.com 127.0.0.1 cms.jd.com