
学习这本书,然后自己对其中的代码加了一些注释,便于学习和理解。
代码可以在https://github.com/greyli/helloflask/下载到
先看两张书上的图:
第一张图是C/S架构的图,C(Client,用户),S(Server,服务器)
第二张是Flask Web的工作流程
客户端先通过http,用URL向服务器端发送请求,然后服务器端通过一个约定好的叫做WSGI的标准,与Flask程序交互,返回Flask处理好的东西,然后再通过Web服务器传回客户端浏览器。
MVC是一种常用的框架模式,MTV是Flask所用的框架模式,但是二者相差不大。
- MVC的V(view)对应的是MTV的T(template),二者都起视图展示的作用,只是叫法不同,在Flask中,template主要由待渲染的HTML文件组成。
- MVC的C(control)对应的是MTV的V(view),这里要注意的是,这个view是视图函数,其实它起一个控制器的作用,视图函数的意思就是用来控制视图的函数。
- MVC和MTV的M指的是模型,用来处理程序需要 *** 作的数据,先按下不表,以后再提到。
import os
try:
from urlparse import urlparse, urljoin
except importError:
from urllib.parse import urlparse, urljoin
from jinja2 import escape
from jinja2.utils import generate_lorem_ipsum
from flask import Flask, make_response, request, redirect, url_for, abort, session, jsonify
app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'secret string')#这个和cookie还有session有关,用来设置session秘钥
# get name value from query string and cookie #从query string和cookie中,查询name变量
#query string指的是查询字符串,详见P29,比如URL:http://helloflask.com/hello?name=Grey,其中的?name=Grey
@app.route('/')#一般来讲必须有主页的视图,不然容易报错,这里是让/主页和/'hello',共用了一个视图函数,会返回相同的效果。
@app.route('/hello')
def hello():
name = request.args.get('name')#args从url的query中找到name后面的键值,这里不能用cookies,因为还没生成对应的cookies
if name is None:#记得判断如果为空,则默认为human
name = request.cookies.get('name', 'Human')#第一个参数是self key,即键,就设置为name就行了,# 第二个参数是default值,get函数既有返回值,又能进行赋值处理
#如果后面生成了cookie的话,这里可以用cookies(下面那个set_cookie视图函数可以生成cookie
response = 'Hello, %s!' % escape(name) # escape name to avoid XSS
# return different response according to the user's authentication status
# 根据用户的身份验证状态返回不同的响应
if 'logged_in' in session:
response += '[Authenticated]'
else:
response += '[Not Authenticated]'
return response
# redirect
@app.route('/hi')#重定向,把hi定向到hello里面
def hi():
return redirect(url_for('hello'))
# use int URL converter
#可以在url里面设置变量,含义为,在year前面加一个int转换器,这样它就从url变成了一个int变量,在视图函数中可以直接调用这个变量
@app.route('/goback/')
def go_back(year):
return 'Welcome to %d!' % (2021 - year)
# use any URL converter
@app.route('/colors/')#变量的另一个例子,相当于是用了个any向量(行)
def three_colors(color):
return 'Love is patient and kind. Love is not jealous or boastful or proud or rude.
'
# return error response
@app.route('/brew/')#未指定类型的变量
def teapot(drink):
if drink == 'coffee':
abort(418)
else:
return 'A drop of tea.'
# 404
@app.route('/404')
def not_found():
abort(404)
# return response with different formats
#不同格式的响应
@app.route('/note', defaults={'content_type': 'text'})#content_type和query_string之类的一样,都是url里面的东西,这里用defaults在调用这个参数的时候给它赋一个默认的值
@app.route('/note/')#如果输入的不是默认值的话,比如note/html,则显示出来HTML格式的
def note(content_type):#python的三个单引号表示直接输出
content_type = content_type.lower()#这里注意细节,用lower()函数将其转化为小写,因为windows和mac os的url是不区分大小写的,但是linux和unix的路径部分是区分的
if content_type == 'text':
body = '''Note
to: Peter
from: Jane
heading: Reminder
body: Don't forget the party!
'''
#make_response用来设置响应,并标记其响应头,比如content-type就是响应头中的一个,可以在网页中用f12测试一下
response = make_response(body)#用make_response函数生成响应对象
#make_response的返回的response的常用方法和属性在P47
response.mimetype = 'text/plain'#text/plain代表纯文本格式
elif content_type == 'html':
body = '''
Note
to: Peter
from: Jane
heading: Reminder
body: Don't forget the party!
'''
response = make_response(body)
response.mimetype = 'text/html'
elif content_type == 'xml':
body = '''
Peter
Jane
Reminder
Don't forget the party!
'''
response = make_response(body)
response.mimetype = 'application/xml'
elif content_type == 'json':
body = {"note": {
"to": "Peter",
"from": "Jane",
"heading": "Remider",
"body": "Don't forget the party!"
}
}
response = jsonify(body)
# equal to:
# response = make_response(json.dumps(body))
# response.mimetype = "application/json"
else:
abort(400)
return response
# set cookie
@app.route('/set/')#定义了一个变量,用来设置cookie
def set_cookie(name):
response = make_response(redirect(url_for('hello')))
#调用response的用来set_cookie的方法,将变量name传到名为name的cookie里,打开浏览器f12就能看的
response.set_cookie('name', name)
return response
#处理登录问题要注意加密,要用session而不是cookie
# log in user
@app.route('/login')
def login():
session['logged_in'] = True #这个session相当于一个字典,这里直接自定义一个名为'logged_in'的东西(根据习惯命名即可),让它作为键,然后值是一个布尔类型
return redirect(url_for('hello')) #这里是根据开发时具体的情况而定,一般会在登录后返回登录前处在的界面,这里是返回了主页
# protect view
@app.route('/admin')
def admin():
if 'logged_in' not in session:#用了一个字典的查询 *** 作
abort(403)
return 'Welcome to admin page.'#后面具体开发的时候,要填上对应的模板和表单
# log out user
@app.route('/logout')
def logout():
if 'logged_in' in session:
session.pop('logged_in')#字典的pop *** 作,其实字典里面是一个平衡树
return redirect(url_for('hello'))
# AJAX
@app.route('/post')
def show_post():
post_body = generate_lorem_ipsum(n=2)
return '''
A very long post
%s
''' % post_body
@app.route('/more')
def load_post():
return generate_lorem_ipsum(n=1)
# redirect to last page
@app.route('/foo')
def foo():
return 'Foo pageDo something and redirect'
% url_for('do_something', next=request.full_path)
@app.route('/bar')
def bar():
return 'Bar pageDo something and redirect'
% url_for('do_something', next=request.full_path)#这里是一个函数嵌套的情况
#最外面是url_for,给其中加了一个名为next的参数,这就相当于是一个外层的变量,里面存的是当前页面的完整路径
#然后执行return函数,跳转到了do-something,实际开发中应该会跳转到某个新的页面,就放在这一层里,然后处理完之后,在do-something里面调用了redirect_back
#然后又执行redirect_back,因为内层函数可以调用外层的变量,所以在这一层还是可以调用next变量
@app.route('/do-something')
def do_something():
# do something here
return redirect_back()
#依然要注意安全问题,防止开放重定向漏洞
def is_safe_url(target):
ref_url = urlparse(request.host_url)
test_url = urlparse(urljoin(request.host_url, target))
return test_url.scheme in ('http', 'https') and
ref_url.netloc == test_url.netloc
def redirect_back(default='hello', **kwargs):
for target in request.args.get('next'), request.referrer:#这里相当于用for循环尝试两种可能,target相当于平时的i变量
if not target:
continue
if is_safe_url(target):
return redirect(target)
return redirect(url_for(default, **kwargs))
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)