一、装饰器decorator
在Python中装饰器,在Java中称为注解;
# -*- encoding=UTF-8
'''
* 用来传递任意个无名字参数,这些参数会一个Tuple的形式访问。
**用来处理传递任意个有名字的参数,这些参数用dict来访问
'''
def log(level, *args, **kvargs):
def inner(func):
def wrapper(*args, **kvargs):
print level, ': before calling ', func.__name__
print level, ': args:', args, 'kvargs:', kvargs
func(*args, **kvargs)
print level, ': after calling ', func.__name__
print ''
return wrapper
return inner
@log(level='INFO')
def hello(name, msg):
print 'hello', name, msg
if __name__ == '__main__':
hello(name='nowcoder', msg='i miss you')
输出结果:
INFO : before calling hello
INFO : args: () kvargs: {'msg': 'i miss you', 'name': 'nowcoder'}
hello nowcoder i miss you
INFO : after calling hello
二、Flask安装和框架
1 官网
中文版本
http://dormousehole.readthedocs.io/en/latest/
2 框架
无论是访问Web页面都是一个request;
3 安装
在命令行窗口键入pip install flask;
三、路由routing
1 /结尾自动补齐???
2 多映射
@app.route('/')
@app.route('/index/')
3 参数变量
@app.route('/index/<uid>')
4 变量类型
@app.route('/index/<int:uid>')
举例:
# 导入flask模块的Flask类
from flask import Flask
# 定义一个应用,一个网站就是一个应用
app = Flask(__name__)
# 指定一个路径的映射
@app.route('/')
def index():
return 'hello'
# 多映射
@app.route('/')
@app.route('/index')
def index():
return 'hello'
# 传递传参数变量<>
@app.route('/profile/<uid>')
def profile(uid):
return 'profile: ' + uid
# 转化profile/后接收的数据类型
@app.route('/profile/<int:uid>')
def profile(uid):
return 'profile: ' + uid
if __name__ =='__main__':
# 运行,开启debug模式
app.run(debug=True)
四、HTTP Method
一般网站只用GET和POST,代表获取和更新;
HTML的form只支持GET和POST;
1 GET
获取接口信息;
2 HEAD
紧急查看接口HTTP的头;
3 POST
提交数据到服务器;
4 PUT(少用)
支持幂等性的POST;
5 DELETE(少用)
删除服务器上的资源;
6 OPTIONS(少用)
查看支持的方法;
补充:
在Chrome浏览器上安装Postman,用于捕获HTTP请求;
使某方法支持POST,则需显式指定;
@app.route('/index', methods=['POST', 'get'])
五、静态和模板文件
1 静态
默认目录:static/templates
文件:css/js/images
2 模板
默认目录:templates
文件::*.html,*.htm
六、Jinja2
1 模板语法
{{变量/表达式}}
{%语法%}
{#注释#}
#开头,行语法表达式:app.jinja_env.line_statement_prefix = '#'
2 语法
2.1 for
loop.index,loop.index0
loop.first,loop.cycle
{% for color in colors: %}
color{{ loop.index }}:{{color}}<br>
{% endfor %}
2.2 filter
默认目录:templates
文件:*.html,*.htm
2.3 模板继承
include
extends
2.4 call/macro
{% macro render_color(color) -%}
<div>This is color: {{color}}
{{ caller() }}</div>
{%- endmacro %}
{% for color in colors: %}
{% call render_color(color) %}
render_color_demo
{% endcall %}
{% endfor %}
七、requsts和response
导入request和make_response;
1 request对象
method:当前请求方法(POST,GET等)
url:当前链接地址
path:当前链接的路径
environ:潜在的WSGI环境
headers:传入的请求头作为字典类对象
data:包含传入的请求数据作为
args:请求链接中的参数(GET参数),解析后
form:form提交中的参数,解析后
values:args和forms的集合
json:json格式的body数据,解析后
cookies:cookie读取
2 response对象
2.1 生成response对象
response = make_response(render_template(index.html))
2.2 方法
status:响应状态
headers:响应头,设置http字段
set_coockie:设置一个cookie
举例:
#-*-coding:utf8-*-
from flask import Flask, flash, request, make_response
app = Flask(__name__)
app.jinja_env.line_statement_prefix = '#'
app.secret_key = '123'
@app.route('/request')
def requestdemo():
key = request.args.get('key', 'defaultkey')
res = request.args.get('key', 'defaultkey')+'<br>'
res+= request.url+'<br>'+request.path+'<br>'
response=make_response(res)
response.set_cookie('rainbow', key)
response.headers['rainbow'] = 'twc' # 在Chrome浏览器的检查中网络的Headers可以查看到
return response
if __name__ == '__main__':
app.run(debug=True)
八、重定向和错误
导入redirect方法;
1 重定向
redirect(location, code)
其中,location是链接路径,code取值有301和302,301——永久转移,302——临时转移;
#-*-coding:utf8-*-
from flask import Flask, flash, redirect
app = Flask(__name__)
app.jinja_env.line_statement_prefix = '#'
app.secret_key = '123'
@app.route('/newpath')
def newpath():
return 'newpath'
@app.route('/re/<int:code>')
def redirect_demo(code):
return redirect('/newpath', code=code)
if __name__ == '__main__':
app.run(debug=True)
2 error
默认情况下,每个错误代码会显示一个黑白错误页面,但用户体验不好;
若要定制错误页面,可以使用 errorhandler() 装饰器;
创建一个404.html文件用于定制的错误页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>你要找的页面去火星了</title>
</head>
<body>
<h2>抱歉,该页面不存在</h2>
</body>
</html>
在程序中使用errorhandler()装饰器进行错误页面捕获;
#-*-coding:utf8-*-
from flask import Flask, flash, render_template
app = Flask(__name__)
app.jinja_env.line_statement_prefix = '#'
app.secret_key = '123'
@app.errorhandler(404)
def not_found(e):
return render_template('404.html')
if __name__ == '__main__':
app.run(debug=True)
九、Flash Message
Flask提供消息闪现机制,方便在应用中消息提示;
首先导入flash方法,再对secret_key进行赋值,以对消息加密;
然后定义一个路由,使用flash(msg)方法,并返回模板;
flaskApp.py代码如下,功能是对输入的用户名和密码进行相应提示;
#-*-coding:utf8-*-
from flask import Flask, flash, render_template,request
app = Flask(__name__)
app.secret_key = '123'
@app.route('/')
def hello_user():
flash("Welcomt to China")
return render_template("index.html")
@app.route('/login', methods=['POST'])
def login():
form=request.form
username=form.get('username')
password=form.get('password')
if not username:
flash("Please enter username")
return render_template("index.html")
if not password:
flash("Please enter password")
return render_template("index.html")
if username=="wencheng" and password=="123":
flash("Login succeed")
return render_template("index.html")
else:
flash("Username or password is not correcct")
return render_template("index.html")
if __name__ == '__main__':
app.run()
index.html文件代码如下,get_flashed_messages从python程序获取传递的信息,呈现给用户的样式在这里指定;
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>Hello Login</h1>
<!--
form标签的action属性是指提交表单时将数据提交到指定页面,这里是/login页面
form标签的method属性是规定如何发送表单数据,有post/get
-->
<form action="/login" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" name="submit">
</form>
<h3>{{get_flashed_messages()[0]}}</h3>
</body>
</html>
十、Log
1 logging
1.1 Logger对象
其中,lvl可取值为logging.NOTSET(0)、logging.DEBUG(10)、logging.INFO(20)、logging.WARNING(30)、logging.ERROR(40)、logging.CRITICAL(50);setLevel(lvl) 设置logger级别
其中,msg是字符串;debug(msg) 记录DEBUG级别以上的日志
info(msg) 记录INFO级别以上的日志
warning(msg) 记录WARNING级别以上的日志
error(msg) 记录ERROR级别以上的日志
critical(msg) 记录CRITICAL级别以上的日志
log(lvl, msg) 记录指定整数值代表的日志级别以上的日志
1.2 Handler对象
其中,form是logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]')setLevel(lvl) 设置handler级别
setFormatter(form) 设置日志输出形式
debug(msg) 记录DEBUG级别以上的日志
info(msg) 记录INFO级别以上的日志
warning(msg) 记录WARNING级别以上的日志
error(msg) 记录ERROR级别以上的日志
critical(msg) 记录CRITICAL级别以上的日志
log(lvl, msg) 记录指定整数值代表的日志级别以上的日志
1.3 模块级方法looging
basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='license.log',
filemode='w') 配置logging系统
debug(msg) 记录DEBUG级别以上的日志
info(msg) 记录INFO级别以上的日志
warning(msg) 记录WARNING级别以上的日志
error(msg) 记录ERROR级别以上的日志
critical(msg) 记录CRITICAL级别以上的日志
log(lvl, msg) 记录指定整数值代表的日志级别以上的日志
2 flask-logging
2.1 logging to a file
RotatingFileHandler(path) 将日志文件中的文本进行回滚处理
其中,path指定日志存放路径及日志文件名;
FileHandler(path) 将错误信息加入到一个文件中
举例:
#-*-coding:utf8-*-
from flask import Flask
import logging
from logging.handlers import RotatingFileHandler
app = Flask(__name__)
app.jinja_env.line_statement_prefix = '#'
app.secret_key = '123'
@app.route('/log/<level>/<msg>')
def log(level, msg):
dict = {'warn': logging.WARN, 'error':logging.ERROR, 'info': logging.INFO}
if(dict.has_key(level)):
app.logger.log(dict[level], msg)
return 'logged:' + msg
def set_logger():
# RotatingFileHandler将日志文件中的文本资料进行回滚处理
info_file_handler = RotatingFileHandler('F:\\logs\\info.txt')
info_file_handler.setLevel(logging.INFO)
app.logger.addHandler(info_file_handler)
warn_file_handler = RotatingFileHandler('F:\\logs\\warn.txt')
warn_file_handler.setLevel(logging.WARN)
# logger.hanlder(hdlr)增加一个指定的处理器hdlr到该logger
app.logger.addHandler(warn_file_handler)
error_file_handler = RotatingFileHandler('F:\\logs\\error.txt')
error_file_handler.setLevel(logging.ERROR)
app.logger.addHandler(error_file_handler)
if __name__ == '__main__':
set_logger()
app.run(debug=True)
2.2 error mail
在debug模式为‘false’的服务器上,通过引入logging库文件,引入处理类 SMTPHander,当服务器中的app发生了错误报告时,会通过其设置的邮箱地址来将app的后天错误信息发送到指定的server-error@example.com 邮箱中,提醒管理员后台出现错误信息,及时对错误信息进行处理;
举例:
from flask import Flask
import logging
from logging.handlers import SMTPHandler
app = Flask(__name__)
app.jinja_env.line_statement_prefix = '#'
app.secret_key = '123'
@app.route('/index/<level>')
def log(level):
if(level == logging.ERROR or level == logging.CRITICAL)
app.logger.addHandler(mail_handler)
def set_logger():
ADMINS = ['yourname@example.com']
mail_handler = SMTPHandler('127.0.0.1',
'server-error@example.com',
ADMINS, 'YourApplication Failed')
mail_handler.setLevel(logging.ERROR)
if '__name__' == '__main__':
set_logger()
app.run(debug = True)
十一、flask-script
Flask Script扩展提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Python shell,设置数据库的脚本,cronjobs,及其他运行在web应用之外的命令行任务;使得脚本和系统分开;
Flask Script和Flask本身的工作方式类似,只需定义和添加从命令行中被Manager实例调用的命令;
官方文档:http://flask-script.readthedocs.io/en/latest/
1 创建并运行命令
首先,创建一个Python模板运行命令脚本,可起名为manager.py;
在该文件中,必须有一个Manager实例,Manager类追踪所有在命令行中调用的命令和处理过程的调用运行情况;
Manager只有一个参数——Flask实例,也可以是一个函数或其他的返回Flask实例;
调用manager.run()启动Manager实例接收命令行中的命令;
#-*-coding:utf8-*-
from flask_script import Manager
from debug import app
manager = Manager(app)
if __name__ == '__main__':
manager.run()
其次,创建并加入命令;
有三种方法创建命令,即创建Command子类、使用@command修饰符、使用@option修饰符;
第一种——创建Command子类
Command子类必须定义一个run方法;
举例:创建Hello命令,并将Hello命令加入Manager实例;
#-*-coding:utf8-*-
from flask_script import Manager
from flask_script import Command
from debug import app
manager = Manager(app)
class Hello(Command):
'hello world'
def run(self):
print 'hello world'
manager.add_command('hello', Hello())
if __name__ == '__main__':
manager.run()
执行如下命令:
python manager.py hello
> hello world
第二种——使用Command实例的@command修饰符
#-*-coding:utf8-*-
from flask_script import Manager
from debug import app
manager = Manager(app)
@manager.command
def hello():
'hello world'
print 'hello world'
if __name__ == '__main__':
manager.run()
该方法创建命令的运行方式和Command类创建的运行方式相同;
python manager.py hello
> hello world
第三种——使用Command实例的@option修饰符
复杂情况下,建议使用@option;
可以有多个@option选项参数;
#-*-coding:utf8-*-
from flask_script import Manager
from debug import app
manager = Manager(app)
@manager.option('-n', '--name', dest='name', help='Your name', default='world')
@manager.option('-u', '--url', dest='url', default='www.csdn.com')
def hello(name, url):
'hello world or hello <setting name>'
print 'hello', name
print url
if __name__ == '__main__':
manager.run()
运行方式如下:
python manager.py hello
>hello world
>www.csdn.com
python manager.py hello -n sissiy -u www.sissiy.com
> hello sissiy
>www.sissiy.com