1、构造URL(url_for)
一般我们通过一个URL就可以执行到某一个函数。如果反过来,我们知道一个函数,如何去获得这个URL呢?url_for函数就可以帮我们实现这个功能。url_for()函数接收两个及以上的参数,他接收函数名作为第一个参数,接收对应URL规则的命名参数,如果还出现其他的参数,则会添加到URL的后面作为查询参数。
通过构建URL的方式而选择直接在代码中拼URL的原因有两点
- 将来如果修改了URL,但没有修改该URL对应的函数名,就不用到处去替换URL了。
- url_for()函数会转义一些特殊字符和unicode字符串,这些事情url_for会自动的帮我们搞定
指定URL末尾的斜杠
有些URL的末尾是有斜杠的,有些URL末尾是没有斜杠的。这其实是两个不同的URL。
@app.route('/article/')
def articles():
return '文章列表页'
上述例子中,当访问一个结尾不带斜线的URL:/article,会被重定向到带斜线的URL:/article/上去。但是当我们在定义article的url的时候,如果在末尾没有加上斜杠,但是在访问的时候又加上了斜杠,这时候就会抛出一个404错误页面了:
@app.route("/article")
def articles(request):
return "文章列表页面"
上面没有在末尾加斜杠,因此在访问/article/的时候,就会抛出一个404错误。
实例如下:
from flask import Flask, url_for
app = Flask(__name__)
@app.route("/")
def index():
print(url_for("article_list", aid=2, pag=2, t=123)) # 这样获得路由,后期修改路由等成本较小,不用修改所有 /article/2/
# return "hello world"
return "article_list" # 硬编码,后期维护修改成本大
@app.route("/article/<aid>/") # 注意url末尾的/需要添加,防止出错
def article_list(aid):
return "article list {}".format(aid)
@app.route("/detail/<did>/")
def article_detail(did):
print(url_for("index"))
print(url_for("index", next="/"))
return "article detail {}".format(did)
if __name__ == '__main__':
app.run(debug=True)
2、指定HTTP方法
HTTP方法包含:GET、POST、PUT、COPY、HEAD、LINK等等
推荐使用一个小软件:Postman,可以模拟HTTP中的各种方法实现,截图如下:
在@app.route()中可以传入一个关键字参数methods来指定本方法支持的HTTP方法,默认情况下,只能使用GET请求
GET请求和POST请求的区别:
GET : 参数直接体现在url地址中
POST: 参数没有直接体现在url地址中
@app.route("/login/")
def login():
# GET : 参数直接体现在url地址中
# POST: 参数没有直接体现在url地址中
print(type(request.args)) # 字典类型 # <class 'werkzeug.datastructures.ImmutableMultiDict'>
print(request.args.get('username'))
return "login"
当只有默认方法GET请求时候:
# 默认使用的是GET请求
@app.route('/login/')
def login():
return 'login'
使用Postman软件进行测试时候,会显示无响应。
添加POST请求方法之后,使用Postman软件进行测试效果:
# 默认使用的是GET请求
@app.route('/login/',methods=['GET','POST'])
def login():
return 'login'
以上装饰器将让login的URL既能支持GET又能支持POST
说明除了methods列表中的传入方法,其他的方法都不会得到相应。
3、页面跳转和重定向
重定向分为永久性重定向和暂时性重定向,在页面上体现的操作就是浏览器会从一个页面自动跳转到另外一个页面。比如用户访问了一个需要权限的页面,但是该用户当前并没有登录,因此我们应该给他重定向到登录页面。
- 永久性重定向:http的状态码是301,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,你输入www.jingdong.com的时候,会被重定向到www.jd.com,因为jingdong.com这个网址已经被废弃了,被改成jd.com,所以这种情况下应该用永久重定向。
- 暂时性重定向:http的状态码是302,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。
在flask中,重定向是通过flask.redirect(location,code=302)这个函数来实现的,location表示需要重定向到的URL,应该配合之前讲的url_for()函数来使用,code表示采用哪个重定向,默认是302也即暂时性重定向,可以修改成301来实现永久性重定向.
from flask import Flask, url_for, request, redirect
# 页面重定向 登录
@app.route("/sigin1/") # 如果项目之后需要修改此url地址,硬编码方式需要修改的内容较多
def sigin(): # 方法名一般不变 所以在url_for中可以使用这个参数进行重定向
return "sigin——1"
@app.route("/profile/")
def profile():
name = request.args.get("name")
if name:
return name
else:
# 重定向到登录页面
# return redirect("/login_1/") # 当登录的url地址需要修改时,此时这里的url也需要修改 这是硬编码方式
return redirect(url_for("sigin"),code=301) # 当使用url_for这个方法时候,登录的url改变,也不用改变这里参数了
# url_for传参的参数是方法名称,不是url地址名 code是网页响应的状态码
4、关于响应(Response)
视图函数中可以返回以下类型的值:
- Response对象。
- 字符串。其实Flask是根据返回的字符串类型,重新创建一个werkzeug.wrappers.Response对象,Response将该字符串作为主体,状态码为200,MIME类型为text/html,然后返回该Response对象。
- 元组。元组中格式是(response,status,headers)。response为一个字符串,status值是状态码,headers是一些响应头。
- 如果不是以上三种类型。那么Flask会通过Response.force_type(rv,request.environ)转换为一个请求对象。
直接使用Response创建
from flask import make_response
@app.route("/about/") # 如果之后需要修改此url地址,
def about():
# return "xxxxxxx" # 可以返回字符串
# return ['12312'] # 不能返回列表
# return {'name': 'xxxx', 'age': "asd"}
# return ('NAME', 'PYTHON') # 元祖只能返回第一个值
# return ('NAME', 'PYTHON')[1] # 这样可以输出元祖第二个参数
# The return type must be a string, dict, tuple, Response instance, or WSGI callable, but it was a list.
# return (["PYTHON"], "JAVA") # 相当于返回的是列表 报错
# 相当于返回字符串
# return Response("关于我们", status=200, mimetype="text/html") # 相当于返回的是字符串
# return "关于我们", 200 # 与上面的返回结果相同 200 是状态码
return make_response("关于我们")
可以使用make_response函数来创建Response对象,这个方法可以设置额外的数据,比如设置cookie,header信息。
from flask import make_response
@app.route('/about/')
def about():
return make_response('about page')
通过返回元组的形式
@app.errorhandler(404)
def not_found():
return 'not found',404
5、模板
模板是一个web开发必备的模块。因为我们在渲染一个网页的时候,并不是只渲染一个纯文本字符串,而是需要渲染一个有富文本标签的页面。这时候我们就需要使用模板了。在Flask中,配套的模板是Jinja2,Jinja2的作者也是Flask的作者。执行效率高。以下对Jinja2简单介绍。
Flask渲染Jinja模板
要渲染一个模板,通过render_template方法即可
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
# 默认会从templates文件夹目录下面找模板文件
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True, port=8000) # 端口修改一下 区分其他的代码文件中使用中的端口
当访问url的时候,index()函数会在当前目录下的templates文件夹下寻找about.html模板文件。如果想更改模板文件地址,应该在创建app的时候,给Flask传递一个关键字参数template_folder,指定具体的路径。
from flask import Flask, render_template
app = Flask(__name__, template_folder="./test") # 区当前路径下的test文件夹下找模板文件index.html
# template_folder是自己设置的专属路径模板 建议写成绝对路径而不是上面的相对路径
@app.route("/")
def index():
# 默认会从templates文件夹目录下面找模板文件
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True, port=8000) # 端口修改一下 区分其他的代码文件中使用中的端口
6、模板文件参数传递
如果模板文件中有参数需要传递,如何进行传递:
介绍了两种传递参数的方式,因为render_template需要传递的是一个关键字参数,所以第一种方式是顺其自然的。但是当你的模板中要传递的参数过多的时候,把所有参数放在一个函数中显然不是一个好的选择,因此我们使用字典进行包装,并且加两个*号,来转换成关键字参数。
from flask import Flask, render_template
app = Flask(__name__, template_folder="./test")
# template_folder是自己设置的专属路径模板 建议写成绝对路径,而不是上面的相对路径
@app.route("/")
def index():
# 默认会从templates文件夹目录下面找模板文件
return render_template('index.html', username="python", age=18)
if __name__ == '__main__':
app.run(debug=True, port=8000) # 端口修改一下 区分其他的代码文件中使用中的端口
from flask import Flask, render_template
app = Flask(__name__, template_folder="./test")
# template_folder是自己设置的专属路径模板 建议写成绝对路径,而不是上面的相对路径
@app.route("/")
def index():
# 默认会从templates文件夹目录下面找模板文件
context = {
"username": "python",
"age": 18,
}
return render_template('index.html', **context) # **代表绑定关键字
if __name__ == '__main__':
app.run(debug=True, port=8000) # 端口修改一下 区分其他的代码文件中使用中的端口
而index.html中应该这样写参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试网页</title>
</head>
<body>
<h1>{{ username }}</h1>
<h1>{{ age }}</h1>
<h1>{{ age }}</h1>
</body>
</html>
<!--这里的 html文件 只能放在 templates 这个文件夹下-->
以上例子介绍了两种传递参数的方式,因为render_template需要传递的是一个关键字参数,当你的模板中要传递的参数过多的时候,把所有参数放在一个函数中显然不是一个好的选择,因此我们使用字典进行包装,并且加两个*号,来转换成关键字参数。
7、不同数据类型模板传参
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试网页</title>
</head>
<body>
<!--字典嵌套取值-->
<h1>{{books.Python}}</h1>
<h1>{{ books['Python'] }}</h1>
<!--列表取值-->
<h1>{{ book.1 }}</h1>
<h1>{{ book[1] }}</h1>
</body>
</html>
<!--这里的 html文件 只能放在 templates 这个文件夹下-->