1、`add_url_rule(rule,endpoint=None,view_func=None)`
这个方法用来添加url与视图函数的映射。如果没有填写`endpoint`,那么默认会使用`view_func`的名字作为`endpoint`。以后在使用`url_for`的时候,就要看在映射的时候有没有传递`endpoint`参数,如果传递了,那么就应该使用`endpoint`指定的字符串,如果没有传递,那么就应该使用`view_func`的名字。
2、`app.route(rule,**options)`装饰器:
这个装饰器底层,其实也是使用`add_url_rule`来实现url与视图函数映射的。
3、类视图:
3.1、标准类视图:
- 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(视图名字)`中指定的视图名字来作为反转。
-
class ListView01(views.View): def dispatch_request(self): return "list_view" app.add_url_rule("/list01/",view_func=ListView01.as_view('list01')) with app.test_request_context(): print(url_for("list01"))
class ListView01(views.View): def dispatch_request(self): return "list_view" app.add_url_rule("/list01/",endpoint='my_list',view_func=ListView01.as_view('list01')) with app.test_request_context(): print(url_for("my_list"))
- 5. 类视图有以下好处:可以继承,把一些共性的东西抽取出来放到父视图中,子视图直接拿来用就可以了。但是也不是说所有的视图都要使用类视图,这个要根据情况而定。
我们要实现在注册页面和登陆页面都放同一个广告:
实现方式一:
class Login(views.View):
def dispatch_request(self):
return render_template("login.html",adv="这是广告")
class Register(views.View):
def dispatch_request(self):
return render_template('Register.html',adv="这是广告")
app.add_url_rule('/login/',endpoint='login',view_func=Login.as_view('login'))
app.add_url_rule("/register/",endpoint='register',view_func=Register.as_view('register'))
实现方式二:我们可以通过一个父类来将公共的部分集成起来
class ADSView(views.View):
def __init__(self):
super(ADSView,self).__init__()
self.context={
'adv':'这是广告'
}
class Login(ADSView):
def dispatch_request(self):
return render_template("login.html",**self.context)
class Register(ADSView):
def dispatch_request(self):
return render_template('Register.html',**self.context)
如果我们需要在login类中添加新的内容,我们可以通过self.context.update()来实现
class ADSView(views.View):
def __init__(self):
super(ADSView,self).__init__()
self.context={
'adv':'这是广告'
}
class Login(ADSView):
def dispatch_request(self):
self.context.update({
'title':'登陆'
})
return render_template("login.html",**self.context)
class Register(ADSView):
def dispatch_request(self):
return render_template('Register.html',**self.context)
3.2、基于请求方法的类视图:
- 1. 基于方法的类视图,是根据请求的`method`来执行不同的方法的。如果用户是发送的`get`请求,那么将会执行这个类的`get`方法。如果用户发送的是`post`请求,那么将会执行这个类的`post`方法。其他的method类似,比如`delete`、`put`。
- 2. 这种方式,可以让代码更加简洁。所有和`get`请求相关的代码都放在`get`方法中,所有和`post`请求相关的代码都放在`post`方法中。就不需要跟之前的函数一样,通过`request.method == 'GET'`。
class LoginView(views.MethodView):
def get(self):
return render_template('login.html')
def post(self):
user=request.form.get('username')
passw=request.form.get('password')
if user=='bj' and passw=='123456':
return render_template('index.html')
else:
return render_template('login.html',error="用户名或者密码错误")
app.add_url_rule('/login/',view_func=LoginView.as_view('login'))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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" name="登陆"></td>
</tr>
</tbody>
</table>
{% if error %}
<p style="color: red">{{ error }}</p>
{% endif %}
</form>
</body>
</html>
改进版1
class LoginView(views.MethodView):
def get(self,error=None):
return render_template('login.html',error=error)
def post(self):
user = request.form.get('username')
passw = request.form.get('password')
print(user, passw)
if user == 'bj' and passw == '123456':
return "登陆成功"
else:
return self.get(error="用户名或者密码错误")
app.add_url_rule('/login/', view_func=LoginView.as_view('login'))
改进版2
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):
user = request.form.get('username')
passw = request.form.get('password')
print(user, passw)
if user == 'bj' and passw == '123456':
return "登陆成功"
else:
return self.__render(error="用户名或者密码错误")
app.add_url_rule('/login/', view_func=LoginView.as_view('login'))
Note:
- render函数前面的“__”表示的是私有方法,即__render()表示一个私有方法。
4、 类视图中的装饰器:
1. 如果使用的是函数视图,那么自己定义的装饰器必须放在`app.route`下面。否则这个装饰器就起不到任何作用。
2. 类视图的装饰器,需要重写类视图的一个类属性`decorators`,这个类属性是一个列表或者元组都可以,里面装的就是所有的装饰器。
from flask import Flask, views, url_for, render_template, request
from functools import wraps
import config
app = Flask(__name__)
app.config.from_object(config)
@app.route('/')
def hello_world():
return 'Hello World'
# 自定义一个装饰器,只有username==‘bj'才能进入个人界面
def login_required(func):
@wraps(func)
def wrappers(*args,**kwargs):
username=request.args.get('username')
if username=='bj':
return '进入个人界面'
else:
return "请登陆"
return wrappers
@app.route('/self_me/')
@login_required
def self_me():
return '我的界面'
if __name__ == '__main__':
app.run()
如果给自己定义的类视图添加装饰器呢?
from flask import Flask, views, url_for, render_template, request
from functools import wraps
import config
app = Flask(__name__)
app.config.from_object(config)
@app.route('/')
def hello_world():
return 'Hello World'
# 自定义一个装饰器,只有username==‘bj'才能进入个人界面
def login_required(func):
@wraps(func)
def wrappers(*args,**kwargs):
username=request.args.get('username')
if username=='bj':
return '进入个人界面'
else:
return "请登陆"
return wrappers
@app.route('/self_me/')
@login_required
def self_me():
return '我的界面'
# 自定义的类视图添加装饰器
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()