oldboy:s9day114

参考博客:https://www.cnblogs.com/wupeiqi/articles/7552008.html

一、Flask简介

1.安装Flask

  1. pip install flask

Flask:

  - 短小精悍、可扩展性强的一个Web框架。

  - 依赖wsgi:werkzurg(安装Flask时,这些依赖也会被自动安装)

2.Werkzurg服务器

单独使用Werkzurg服务器:

  1. from werkzeug.wrappers import Request, Response
  2. from werkzeug.serving import run_simple
  3.  
  4. @Request.application
  5. def run(request):
  6. return Response('Hello World')
  7.  
  8. if __name__ == '__main__':
  9. run_simple('localhost', 4000, run)

3.实现简单页面请求

  1. from flask import Flask
  2.  
  3. # 创建一个Flask实例,参数是为这个实例定义一个名字,一般以__name__来指定
  4. app = Flask(__name__)
  5.  
  6. # 利用装饰器,绑定路由
  7. @app.route('/index')
  8. def index():
  9. return "HelloWorld"
  10.  
  11. if __name__ == '__main__':
  12. # 开始运行
  13. app.run()

二、简单使用Flask

1.默认模板目录

Flask默认使用templates作为模板目录。当我们要返回html页面时,默认去该文件夹下找模板文件:

  1. from flask import Flask, render_template
  2.  
  3. # 创建一个Flask实例,参数是为这个实例定义一个名字,一般以__name__来指定
  4. app = Flask(__name__)
  5.  
  6. @app.route('/login')
  7. def login():
  8. return render_template('login.html')
  9.  
  10. if __name__ == '__main__':
  11. # 开始运行
  12. app.run()

2.修改模板目录

在Django中,我们是在setting配置文件中去修改。而在Flask中,我们可以以以下方式修改:

  1. # 创建一个Flask实例,参数是为这个实例定义一个名字,一般以__name__来指定
  2. app = Flask(__name__, template_folder='mytempfile')

我们查看一下Flask类的构造函数:

  1. def __init__(
  2. self,
  3. import_name,
  4. static_url_path=None,
  5. static_folder='static',
  6. static_host=None,
  7. host_matching=False,
  8. subdomain_matching=False,
  9. template_folder='templates',
  10. instance_path=None,
  11. instance_relative_config=False,
  12. root_path=None
  13. ):

可以看到,默认的模板目录参数就是"templates"。

3.Flask接受POST请求、获取请求数据

在Flask中,默认只允许接收GET请求,如果我们先接收POST请求,则需要设置。

在视图函数中获取请求数据时,我们需要导入request模块,而不是通过参数传递request。这是个Django不同的地方。

  1. from flask import Flask, render_template, request
  2.  
  3. app = Flask(__name__)
  4.  
  5. @app.route('/login', methods=['GET', 'POST'])
  6. def login():
  7. # 这里的请求数据和Django中不一样,Flask是通过上下文来管理的,request不是参数,而是导入的模块
  8. if request.method == 'GET':
  9. pass
  10.  
  11. if request.method == 'POST':
  12. pass
  13.  
  14. if __name__ == '__main__':
  15. # 开始运行
  16. app.run()

4.获取GET数据和POST数据

视图函数:

  1. from flask import Flask, render_template, request, redirect
  2.  
  3. app = Flask(__name__)
  4.  
  5. @app.route('/login', methods=['GET', 'POST'])
  6. def login():
  7. # 这里的请求数据和Django中不一样,Flask是通过上下文来管理的,request不是参数,而是导入的模块
  8. if request.method == 'GET':
  9. # request.args对应django中的request.GET
  10. # request.args.get('user)
  11. return render_template('login.html')
  12. if request.method == 'POST':
  13. user = request.form.get('user')
  14. pwd = request.form.get('pwd')
  15. if user == 'leokale' and pwd == '':
  16. return redirect('/index')
  17. else:
  18. return render_template('login.html', error="用户名或密码错误")
  19. # 也可以传多个值(使用字典),但和Django不一样的地方是要解包
  20. # return render_template('login.html', **{"error": "用户名或密码错误"})
  21.  
  22. @app.route('/index')
  23. def index():
  24. return '<h2>欢迎登录</h2>'
  25.  
  26. if __name__ == '__main__':
  27. # 开始运行
  28. app.run()

注意几个和django框架不一样的地方:

1)需要在装饰器中传入methods参数,用来允许接收哪些请求

2)request.args和request.form分别对应django中的request.GET和request.POST

3)redirect跳转和django基本一致

4)模板渲染回传给页面的参数,可以单独传一个,也可以使用字典拆包的形式传入多个(django中参数为字典)

对应html代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Login</title>
  6. </head>
  7. <body>
  8. <h1>登录页面</h1>
  9. <form method="POST">
  10. <input type="text" name="user"/>
  11. <input type="password" name="pwd"/>
  12. <input type="submit" value="登录"/>{{error}}
  1. </form> </body> </html>

5.静态文件

Flask中静态文件默认放在static目录下,如果要修改,也是修改Flask实例化时的参数。

  1. app = Flask(__name__,static_folder='mystatic')

只需要将目录名和这个参数值对应上即可。

但是注意,我们在html中写图片请求连接时使用的url默认是和static_folder一致的:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>INDEX</title>
  6. </head>
  7. <body>
  8. <h2>欢迎访问</h2>
  9. <img src="/mystatic/111.png">
  10. </body>
  11. </html>

但实际上,我们也可以通过一个参数来修改:

  1. app = Flask(__name__, static_folder='mystatic', static_url_path='/vvvvv')

我们将其修改为'/vvvvv',此时html中也要修改为'/vvvvv':

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>INDEX</title>
  6. </head>
  7. <body>
  8. <h2>欢迎访问</h2>
  9. <img src="/vvvvv/111.png">
  10. </body>
  11. </html>

6.Flask中的session

  1. from flask import Flask, render_template, request, redirect, session
  2.  
  3. app = Flask(__name__, static_folder='mystatic', static_url_path='/vvvvv')
  4.  
  5. @app.route('/login', methods=['GET', 'POST'])
  6. def login():
  7. # 这里的请求数据和Django中不一样,Flask是通过上下文来管理的,request不是参数,而是导入的模块
  8. if request.method == 'GET':
  9. # request.args对应django中的request.GET
  10. # request.args.get('user)
  11. return render_template('login.html')
  12. if request.method == 'POST':
  13. user = request.form.get('user')
  14. pwd = request.form.get('pwd')
  15. if user == 'leokale' and pwd == '':
  16. session['user'] = user
  17. return redirect('/index')
  18. else:
  19. return render_template('login.html', error="用户名或密码错误")
  20. # 也可以传多个值(使用字典),但和Django不一样的地方是要解包
  21. # return render_template('login.html', **{"error": "用户名或密码错误"})
  22.  
  23. @app.route('/index')
  24. def index():
  25. user = session.get('user')
  26. if not user:
  27. return redirect('/login')
  28. return render_template('index.html')
  29.  
  30. if __name__ == '__main__':
  31. # 开始运行
  32. app.run()

Flask中session的使用和django很类似,但Flask中的session是导入的模块。

注意,Flask的session默认是保存在加密的cookie中的,可以参照django相关的介绍:https://www.cnblogs.com/leokale-zz/p/12082478.html

这里要使用加密的cookie,又需要设置MD5加盐中的盐,否则会报错:

  1. RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
  2. 127.0.0.1 - - [20/Jan/2020 00:27:46] "POST /login HTTP/1.1" 500 -

我们需要在代码中加上加密设置:

  1. app = Flask(__name__, static_folder='mystatic', static_url_path='/vvvvv')
  2. app.secret_key = "sndjkfn" # MD5加密的盐

此时就可以使用加密cookie来保存session了。

三、Flask的配置文件

1.通过importlib导入指定模块

在setting.py文件中有如下代码:

  1. class Foo(object):
  2. DEBUG = True
  3. TEST = False

我们如果在其他模块中通过importlib导入Foo类,获取其中的DEBUG和TEST的值:

  1. import importlib
  2.  
  3. # 给定类所处模块
  4. path = 'setting.Foo'
  5.  
  6. # 分割path,获取模块名和类名
  7. (m, c) = path.rsplit('.', maxsplit=1)
  8. # 导入模块
  9. m = importlib.import_module(m)
  10. # 获取类
  11. cls = getattr(m, c)
  12.  
  13. # 遍历类中的属性,我们要获取的属性是大写的,所以使用isupper判断
  14. for key in dir(cls):
  15. if key.isupper():
  16. print(key, getattr(cls, key))

这样,我们就使用importlib库动态的导入模块,并获取了其中的Foo类,以及其中的类属性。

Flask的配置文件也是通过这种方式来加载的(很多框架的配置文件都是通过这种方式加载)。

2.Flask默认的配置信息

Flask默认的配置信息:

  1. from flask import Flask, request, render_template
  2.  
  3. app = Flask(__name__)
  4. # app.config获取所有配置信息
  5. print(app.config)
  6. # 可以通过这种方式修改
  7. app.config['DEBUG'] = True

app.config配置内容:

  1. {
  2. 'ENV': 'development',
  3. 'DEBUG': False,
  4. 'TESTING': False,
  5. 'PROPAGATE_EXCEPTIONS': None,
  6. 'PRESERVE_CONTEXT_ON_EXCEPTION': None,
  7. 'SECRET_KEY': None,
  8. 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days = 31), # 默认session的保存周期(对应加密cookie的过期时间)
  9. 'USE_X_SENDFILE': False,
  10. 'SERVER_NAME': None,
  11. 'APPLICATION_ROOT': '/',
  12. 'SESSION_COOKIE_NAME': 'session', # 加密session写到cookie中的key,默认叫session
  13. 'SESSION_COOKIE_DOMAIN': None,
  14. 'SESSION_COOKIE_PATH': None,
  15. 'SESSION_COOKIE_HTTPONLY': True,
  16. 'SESSION_COOKIE_SECURE': False,
  17. 'SESSION_COOKIE_SAMESITE': None,
  18. 'SESSION_REFRESH_EACH_REQUEST': True, # 是否在每次访问的时候刷新session过期时间(即从最后一次访问开始计算过期时间),如果为False,则过期时间时从设置session开始算
  19. 'MAX_CONTENT_LENGTH': None,
  20. 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(seconds = 43200),
  21. 'TRAP_BAD_REQUEST_ERRORS': None,
  22. 'TRAP_HTTP_EXCEPTIONS': False,
  23. 'EXPLAIN_TEMPLATE_LOADING': False,
  24. 'PREFERRED_URL_SCHEME': 'http',
  25. 'JSON_AS_ASCII': True,
  26. 'JSON_SORT_KEYS': True,
  27. 'JSONIFY_PRETTYPRINT_REGULAR': False,
  28. 'JSONIFY_MIMETYPE': 'application/json',
  29. 'TEMPLATES_AUTO_RELOAD': None,
  30. 'MAX_COOKIE_SIZE': 4093
  31. }

3.使用自定义配置文件

使用以下方式为其指定一个自定义配置文件:

  1. from flask import Flask, request, render_template
  2.  
  3. app = Flask(__name__)
  4. # app.config获取DEBUG,默认为False
  5. print(app.config['DEBUG'])
  6. # 通过from_object绑定一个类作为配置对象,其中DEBUG为True
  7. app.config.from_object("setting.Myconfig")
  8. # 再次获取DEBUG,为True
  9. print(app.config['DEBUG'])

这里使用setting模块中的Myconfig类作为其配置文件。from_object源码就是使用的1.中的方式对setting模块进行导入,然后获取Myconfig中的属性值。

setting模块中,我们还可以根据需求,使用多个类来区分不同场景下的配置:

  1. class BaseConfig(object):
  2. # DEV和PROD场景下,相同的配置
  3. XXX = False
  4.  
  5. # 开发环境下的配置
  6. class DevConfig(BaseConfig):
  7. DEBUG = True
  8. TEST = True
  9.  
  10. # 生产环境下的配置
  11. class ProdConfig(BaseConfig):
  12. DEBUG = False
  13. TEST = False

在使用的时候,我们只需要根据场景切换即可:

  1. # 开发环境使用DevConfig配置
  2. app.config.from_object("setting.DevConfig")
  3.  
  4. # 生产部署环境使用ProdConfig配置
  5. app.config.from_object("setting.ProdConfig")

4.其他配置文件的使用

除了3.中所描述的,使用模块中的类来作为配置。还有以下几种方式:

1)from_pyfile

  1. app.config.from_pyfile("setting.py")

例如:

  1. # settings.py
  2.  
  3. DEBUG = True
  4. TEST = False

2)from_envvar

  1. app.config.from_envvar("FLASK_CONFIG_FILE")

例如在Linux下配置环境变量:

  1. export FLASK_CONFIG_FILE='/path/to/config/file'

环境变量的值为python文件(不一定是.py结尾的文件,但内容要是 DEBUG = True这种Python代码格式)名称,内部调用from_pyfile方法。

3)from_json

  1. app.config.from_json("json文件名称")

JSON文件名称,必须是json格式,因为内部会执行json.loads。

4)from_mapping

  1. app.config.from_mapping({'DEBUG':True})

参数为一个字典。

四、Flask的路由系统

在Flask中,路由是通过装饰器加到每个视图函数的:

  1. from flask import Flask, request, render_template
  2.  
  3. app = Flask(__name__)
  4.  
  5. @app.route('/index', methods=['GET', 'POST'])
  6. def hello_world():
  7. if request.method == 'GET':
  8. return render_template('index.html')
  9.  
  10. if __name__ == '__main__':
  11. app.run()

1.@app.route中的endpoint

@app.route中的endpoint参数,就相当于django中的name参数,用来反向生成URL。

  1. from flask import Flask, request, render_template, url_for
  2.  
  3. app = Flask(__name__)
  4.  
  5. @app.route('/index', methods=['GET', 'POST'], endpoint='n1')
  6. def hello_world():
  7. print(url_for('n1')) # 打印/index
  8. if request.method == 'GET':
  9. return render_template('index.html')
  10.  
  11. if __name__ == '__main__':
  12. app.run()

其中的url_for相当于django中的reverse函数,用来利用endpoint反向生成url。

注意:如果我们不指定endpoint,则endpoint默认等于视图函数名,这里即"hello_world"。url_for("hello_world")即为"/index"。

2.动态路由

Flask的路由中,我们可以使用动态参数。

  1. from flask import Flask, request, render_template
  2.  
  3. app = Flask(__name__)
  4.  
  5. @app.route('/index/<int:nid>', methods=['GET', 'POST'])
  6. def hello_world(nid):
  7. print(nid)
  8. if request.method == 'GET':
  9. return render_template('index.html')
  10.  
  11. if __name__ == '__main__':
  12. app.run()

Flask是django使用动态路由的方式不同,在django中,动态路由是这样的:'/index/(?P<nid>\d+)'。

注意:<int:nid>中,int表示动态参数的类型,我们的视图函数接收的参数nid为整形,如果不写,则默认为字符串。

动态参数的类型除了有int以外,还有以下几种类型:

  1. @app.route('/user/<username>') # 字符串
  2. @app.route('/post/<int:post_id>') # 整数
  3. @app.route('/post/<float:post_id>') # 浮点数
  4. @app.route('/post/<path:path>') # 路径类型
  5. @app.route('/post/<uuid:uuid>') # UUID

在使用动态路由的时候,也可以使用方向生成url:

  1. url_for("hello_world",nid=777) # 生成/index/777

五、Flask的请求数据

在Flask中,视图函数没有request参数。Flask中的request是直接导入使用的(上下文管理)。

  1. from flask import Flask, request

在视图函数中,可以直接使用request:

  1. #例如请求: http://127.0.0.1:5000/index/2019-03?name=leo
  2. #以下request的属性值为:
  3. request.method # 请求类型
  4. request.args # GET请求的数据
  5. request.args.get('user')
  6. request.form # POST请求的数据
  7. request.form.get('user')
  8. request.values
  9. request.cookies # Cookie数据
  10. request.headers
  11. """
  12. Accept: text/html, application/xhtml+xml, image/jxr, */*
  13. ...
  14. Connection: Keep-Alive
  15. """
  16. request.path # 请求的url "/index/2019-12"
  17. request.full_path # "/index/2019-12?name=leo" 包含query
  18. request.script_root # ""
  19. request.url # "http://127.0.0.1:5000/index/2019-12?name=leo"
  20. request.base_url # "http://127.0.0.1:5000/index/2019-12"
  21. request.url_root #"http://127.0.0.1:5000/"
  22. request.host_url # "http://127.0.0.1:5000/"
  23. request.host # "127.0.0.1:5000"
  24. request.files
  25. obj = request.files['file_name']
  26. obj.save('/var/www/uploads/' + secure_filename(f.filename)) #上传文件

六、Flask的响应

1.Flask的几种常用响应

在Flask中,常用的响应方式有以下几种:

1)响应字符串

  1. return "HelloWorld" # 相当于django中的HttpResponse

2)响应json数据

  1. from flask import jsonify
  2. return jsonify({'k':'v'})
  3. # 或 return json.dumps({'k':'v'})

3)响应渲染模板

  1. from flask import render_template
  2. return render_template('login.html') # 相当于django中的render

4)响应重定向

  1. from flask import redirect
  2. return redirect('/index')

2.设置响应头

在Flask中如何设置响应头,特别是响应字符串的时候,无法设置响应头。

  1. from flask import make_response
  2.  
  3. # 使用响应对象来封装要返回的字符串
  4. obj=make_response("hello world")
  5. # obj=make_response(render_template('index.html'))
  6.  
  7. # 设置响应头的字段xxx
  8. obj.headers['xxx']=''
  9. # 设置cookie
  10. obj.set_cookie('key','value')
  11.  
  12. # 返回obj
  13. return obj

七、jinjia2模板语言

1.循环与字典取值

Jinjia2模板语言和django自带的模板语言很相似,但功能更加强大。语法比较接近于Python。

视图函数代码:

  1. from flask import Flask, request, render_template
  2.  
  3. app = Flask(__name__)
  4.  
  5. USER_INFO = {
  6. 1: {'name': 'Leo', 'age': 32, 'gender': 'male'},
  7. 2: {'name': 'Jane', 'age': 33, 'gender': 'female'},
  8. 3: {'name': 'Jake', 'age': 12, 'gender': 'male'},
  9. 4: {'name': 'Alex', 'age': 45, 'gender': 'male'},
  10. 5: {'name': 'Lilei', 'age': 77, 'gender': 'female'}
  11. }
  12.  
  13. @app.route('/users', methods=['GET', 'POST'])
  14. def user_list():
  15. if request.method == 'GET':
  16. return render_template('users.html', user_list=USER_INFO)
  17.  
  18. if __name__ == '__main__':
  19. app.run()

我们创建了一个字典,并返回给模板进行渲染。

html模板代码:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Users</title>
  6. </head>
  7. <body>
  8. <h2>用户列表</h2>
  9. <table>
  10. <thead>
  11. <tr>
  12. <th>ID</th>
  13. <th>名字</th>
  14. <th>岁数</th>
  15. <th>性别</th>
  16. </tr>
  17. </thead>
  18. <tbody>
  19. {% for k,v in user_list.items() %}
  20. <tr>
  21. <td>{{ k }}</td>
  22. <td>{{ v.name }}</td>
  23. <td>{{ v.age }}</td>
  24. <td>{{ v.gender }}</td>
  25. </tr>
  26. {% endfor %}
  27. </tbody>
  28. </table>
  29. </body>
  30. </html>

可以看到,使用for循环的方法和django模板语言是一样的。

注意,user_list.items()这个括号一定要有,这和Python一样。

在取值的时候,使用{{ v.name }}这种形式可以获取字典中字段的值。在Jinjia2中,还可以使用{{ v.get('name','默认') }}以及{{ v['name'] }}的形式来取值,和Python基本一致。

2.数组取值

除了1.中所述的用法,这里补充一些用法:

  1. {{ list.0 }} # django模板语言风格取index为0的元素
  2. {{ list[0] }} # python风格取index为0的元素

列表按索引取元素,两种风格都支持。

2)XSS问题

当数据为html标签时:

  1. # data = "<input type='text' />"
  2. {{ data }} # 显示字符串<input type='text' />
  3. {{ data|safe }} # 显示input标签元素

Flask默认帮我们做了XSS,要返回标签格式的字符串,在模板语言中使用"|safe"。

当然,也可以在后端python中使用Markup来传递安全的标签字符串(类似django中的mark_safe):

  1. from flask import Markup
  2.  
  3. Markup("<input type='text' />") # 相当于django中的mark_safe

3.传递函数引用并调用

当我们在视图函数中传递给模板的参数是一个函数引用时:

例如:

  1. def func(arg):
  2. return arg**2
  3.  
  4. # 视图函数index
  5. def index():
  6. return render_template("index.html",func=func) #将func函数引用传递到模板

Jinjia2模板语言调用func:

  1. {{ func(6) }} # 显示36

虽然Jinjia2可以方便的调用函数(比django模板语言方便)。但是如果有多个页面都要调用这个函数,则每个对应的视图函数都要将该函数的引用传递给模板。则可以使用全局的模板函数(类似django中定义模板函数)。

4.全局模板函数

1)@app.template_global()装饰器

使用@app.template_global()装饰器,可以将自定义函数变为全局的模板函数,直接可以在模板语言中调用。

  1. @app.template_global()
  2. def my_add(a,b)
  3. return a+b

在模板中调用:

  1. {{ my_add(1,9) }} # 显示10

2)@app.template_filter()装饰器

还有另一种装饰器@app.template_filter(),和template_global差不多,但是在模板语言中的调用方式不同:

  1. {{ 1|my_add(9) }} # 显示10

这两种方式在Jinjia2中其实效果差不多。

我们可以这样理解

  @app.template_global装饰的模板函数,对应的是django中 @register.simple_tag装饰的模板函数(但由于django模板语言在调用模板函数时,不是使用括号来包裹参数,所以无法作为if的条件)。

  @app.template_filter装饰的模板函数,对应的是django中 @register.filter装饰的模板函数(形式差不多)

由于Jinjia2中传参的方式和python很像,所以两种方式都可以作为if的条件。如下:

  1. # tempalte_global装饰的my_add
  2. {% if my_add(1,9) %}
  3. {% endif %}
  4.  
  5. # tempalte_filter装饰的my_add
  6. {% if 1|my_add(9) %}
  7. {% endif %}

5.定义宏(函数)

Jinjia2模板语言支持定义宏(其实就是定义函数):

  1. <!-- 使用macro定义一个宏(相当于python的def定义函数) -->
  2. {% macro my_func(name,type='text',value='') %}
  3. <input type="{{ type }}" name="{{ name }}" value="{{ value }}"/>
  4. {% endmacro %}
  5. <!-- macro定义的函数,默认是不执行的,需要手动调用 -->
  6. {{ my_func('n1') }}
  7. {{ my_func("n2",type="button",value='确定') }}

也就是说Jinjia2不仅可以支持在后台Flask中定义全局函数,还可以使用macro直接在模板中定义函数。

八、使用装饰器给视图函数添加验证功能

1.简单装饰器的问题

  1. # 最简单的装饰器
  2. def auth(func):
  3. def inner(*args, **kwargs):
  4. ret = func(*args, **kwargs)
  5. return ret
  6. return inner
  7.  
  8. # index函数使用了auth装饰器
  9. @auth
  10. def index():
  11. print('index')
  12.  
  13. # index2函数没有使用auth装饰器
  14. def index2():
  15. print('index2')
  16.  
  17. if __name__ == '__main__':
  18. print(index.__name__) # 打印inner
  19. print(index2.__name__) # 打印index2

可以看到,当一个函数使用了简单装饰器后,打印其函数名,编程了装饰器中的inner。

在这种情况下,会影响我们使用反向生成url的功能,即url_for(视图函数名)。

2.使用functools.wraps

  1. # 导入functools中的wraps
  2. from functools import wraps
  3.  
  4. def auth(func):
  5. # 使用wraps装饰器
  6. @wraps(func)
  7. def inner(*args, **kwargs):
  8. ret = func(*args, **kwargs)
  9. return ret
  10.  
  11. return inner
  12.  
  13. @auth
  14. def index():
  15. print('index')
  16.  
  17. if __name__ == '__main__':
  18. print(index.__name__) # 打印index

使用了functools的wraps装饰器,实际上运行index函数时,还是调用的是inner,但是wraps帮我们将index函数的元信息封装到了inner函数中。

3.使用auth装饰器实现登录验证

  1. from flask import Flask, request, render_template, redirect, session, url_for
  2.  
  3. app = Flask(__name__)
  4. # 使用密码盐(session默认保存在加密cookie中,必须设置密码盐)
  5. app.secret_key = 'snjdkfnjsk'
  6.  
  7. USER_INFO = {
  8. 1: {'name': 'Leo', 'age': 32, 'gender': 'male'},
  9. 2: {'name': 'Jane', 'age': 33, 'gender': 'female'},
  10. 3: {'name': 'Jake', 'age': 12, 'gender': 'male'},
  11. 4: {'name': 'Alex', 'age': 45, 'gender': 'male'},
  12. 5: {'name': 'Lilei', 'age': 77, 'gender': 'female'}
  13. }
  14.  
  15. from functools import wraps
  16.  
  17. # 认证用户是否登录
  18. def auth(func):
  19. @wraps(func)
  20. def inner(*args, **kwargs):
  21. if not session.get('user'):
  22. return redirect(url_for('login'))
  23. ret = func(*args, **kwargs)
  24. return ret
  25.  
  26. return inner
  27.  
  28. # 登录页面
  29. @app.route('/login', methods=['GET', 'POST'])
  30. def login():
  31. if request.method == 'GET':
  32. return render_template('login.html')
  33. user = request.form.get('username')
  34. pwd = request.form.get('password')
  35. # 用户名密码正确,则将用户名写到session中(默认保存在加密cookie中,默认cookie过期时间为31天)
  36. if user == 'leokale' and pwd == '':
  37. session['user'] = user
  38. # 登录成功,跳转到users页面
  39. return redirect('/users')
  40. # 登录失败,返回login页面,并显示用户名或密码错误
  41. return render_template('login.html', error='用户名或密码错误')
  42.  
  43. # users页面,使用auth装饰器进行登录验证
  44. @app.route('/users', methods=['GET', 'POST'])
  45. @auth
  46. def user_list():
  47. if request.method == 'GET':
  48. return render_template('users.html', user_list=USER_INFO)
  49.  
  50. if __name__ == '__main__':
  51. app.run()

1)实现验证装饰器,必须使用functools.wraps装饰器,保证视图函数名不变

2)在auth装饰器中实现验证登录功能(检查session中user是否存在)

3)将auth装饰器应用到需要验证的页面

[Python自学] Flask框架 (1) (Flask介绍、配置、Session、路由、请求和响应、Jinjia2模板语言、视图装饰器)的更多相关文章

  1. flask模板语言,装饰器,路由及配置

    1.模板语言jinja2 Flask中默认的模板语言是Jinja2 1.0 模板传参 from flask import Flask,render_template app = Flask(__nam ...

  2. Flask 模板语言,装饰器

      Jinja2模板语言 # -*- coding: utf-8 -*-   from flask import Flask, render_template, request, redirect,  ...

  3. python三大web框架Django,Flask,Flask,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架

    Python几种主流框架 从GitHub中整理出的15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python We ...

  4. Python的Django框架中的URL配置与松耦合

    Python的Django框架中的URL配置与松耦合 用 python 处理一个文本时,想要删除其中中某一行,常规的思路是先把文件读入内存,在内存中修改后再写入源文件. 但如果要处理一个很大的文本,比 ...

  5. python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)

    12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...

  6. flask之jinjia2模板语言

    flask_jinjia2.py ''' flask中的jinjia2模板语言(和django中模板类似): (1)模板变量{{ }} (2)模板标签{% %} ①for循环遍历 {% for foo ...

  7. Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)

    Python:高级主题之(属性取值和赋值过程.属性描述符.装饰器) 背景 学习了Javascript才知道原来属性的取值和赋值操作访问的“位置”可能不同.还有词法作用域这个东西,这也是我学习任何一门语 ...

  8. ThinkPHP5.0框架开发--第6章 TP5.0 请求和响应

    ThinkPHP5.0框架开发--第6章 TP5.0 请求和响应 第6章 TP5.0 请求和响应 ===================================== 上次复习 1.新建控制器 ...

  9. Flask框架(一):介绍与环境搭建

    1.Flask介绍 Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架. Flask 本身相当于一个内核, ...

随机推荐

  1. 深入理解Java虚拟机内存模型

    前言 本文中部分内容引用至<深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)>第12章,如果有兴趣可自行深入阅读,文末放有书籍PDF版本连接. 一.物理机中的并发 物理机遇到的并 ...

  2. vue2.x中子组件修改父组件通过pops传递过来的值

    首先,父组件向子组件传值 这里面主要是在传值的时候,加上.sync 然后子组件通过 $emit 修改 如此即可完成对父组件的数据操作

  3. 乌班图14更新软件提示错误:https://mirrors.aliyun.com kubernetes-xenial InRelease: 由于没有公钥,无法验证下列签名: NO_PUBKEY 6A030B21BA07F4FB

    提示如下 获取: https://mirrors.aliyun.com kubernetes-xenial InRelease 忽略 https://mirrors.aliyun.com kubern ...

  4. C语言系列之预处理指令、循环左移函数的使用(四)

    本章节将讲两个知识点 第一个知识点:常用的预处理指令 第二个知识点:循环左移右移函数 第一个知识点:预处理指令 一种预处理指令是#define,他把名字A定义为P0,当这个名字出现在源文件的任何地方时 ...

  5. SSH(二)

    SSH框架整合的系统架构,Action.Service.Dao.SessionFactory.DataSource都可以作为Spring的Bean组件管理 使用HibernateDaoSupport基 ...

  6. JSP&Servlet学习笔记----第4章

    HTTP是基于请求/响应的无状态的通信协议. 使服务器记得此次请求与之后请求关系的方式,叫做会话管理. 隐藏域:由浏览器在每次请求时主动告知服务器多次请求间必要的信息.仅适用于一些简单的状态 管理,如 ...

  7. 洛谷P1649 【[USACO07OCT]障碍路线Obstacle Course】

    题目描述 Consider an N x N (1 <= N <= 100) square field composed of 1 by 1 tiles. Some of these ti ...

  8. PySpark Rdd Cheat Sheet Python

  9. HDU_1864_01背包

    http://acm.hdu.edu.cn/showproblem.php?pid=1864 题目好像是输入的数据都是两位小数,先统计能报销的发票,然后把小数*100变成成熟就是01背包问题了. #i ...

  10. 微信小程序—Flex布局

    参考教程:http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html     https://xluos.github.io/demo/flexb ...