1.安装

pip3 install flask

2.十行搞定一个flask项目

from flask import Flask
# 实例化产生一个Flask对象
app = Flask(__name__)
# 将 '/'和视图函数hello_workd的对应关系添加到路由中
@app.route('/') # 1. v=app.route('/') 2. v(hello_world)
def hello_world():
return 'Hello World!' if __name__ == '__main__':
app.run() # 最终调用了run_simple()

右键运行,打开浏览器访问http:127.0.0.1:5000/就可以看到 Hello World 了

3.配置文件

flask中的配置文件是一个flask.config.Config对象(继承字典),有两种配置方式:

方式一:

   app.config['DEBUG'] = True
PS: 由于Config对象本质上是字典,所以还可以使用app.config.update(...)

方式二:

#通过py文件配置
app.config.from_pyfile("python文件名称")
如:
settings.py
DEBUG = True app.config.from_pyfile("settings.py")
#通过环境变量配置
app.config.from_envvar("环境变量名称")
#app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS'])
环境变量的值为python文件名称名称,内部调用from_pyfile方法 app.config.from_json("json文件名称")
JSON文件名称,必须是json格式,因为内部会执行json.loads app.config.from_mapping({'DEBUG': True})
字典格式 app.config.from_object("python类或类的路径") app.config.from_object('pro_flask.settings.TestingConfig') settings.py class Config(object):
DEBUG = False
TESTING = False
DATABASE_URI = 'sqlite://:memory:' class ProductionConfig(Config):
DATABASE_URI = 'mysql://user@localhost/foo' class DevelopmentConfig(Config):
DEBUG = True class TestingConfig(Config):
TESTING = True PS: 从sys.path中已经存在路径开始写 PS: settings.py文件默认路径要放在程序root_path目录,如果instance_relative_config为True,则就是instance_path目录(Flask对象init方法的参数)

4.路由系统

典型写法

@app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')

默认转换器

DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}

路由系统本质

"""
1. decorator = app.route('/',methods=['GET','POST'],endpoint='n1')
def route(self, rule, **options):
# app对象
# rule= /
# options = {methods=['GET','POST'],endpoint='n1'}
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
2. @decorator
decorator(index)
"""
#同理
def login():
return '登录'
app.add_url_rule('/login', 'n2', login, methods=['GET',"POST"])
#与django路由类似
#django与flask路由:flask路由基于装饰器,本质是基于:add_url_rule
#add_url_rule 源码中,endpoint如果为空,endpoint = _endpoint_from_view_func(view_func),最终取view_func.__name__(函数名)

CBV(源码分析)

def auth(func):
def inner(*args, **kwargs):
print('before')
result = func(*args, **kwargs)
print('after')
return result return inner class IndexView(views.View):
methods = ['GET']
decorators = [auth, ] def dispatch_request(self):
print('Index')
return 'Index!' app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint
#或者,通常用此方式
class IndexView(views.MethodView):
methods = ['GET']
decorators = [auth, ] def get(self):
return 'Index.GET' def post(self):
return 'Index.POST'
app.add_url_rule('/index', view_func=IndexView.as_view(name='index')) # name=endpoint

支持正则

#1 写类,继承BaseConverter
#2 注册:app.url_map.converters['regex'] = RegexConverter
# 3 使用:@app.route('/index/<regex("\d+"):nid>') 正则表达式会当作第二个参数传递到类中
from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter app = Flask(import_name=__name__) class RegexConverter(BaseConverter):
"""
自定义URL匹配正则表达式
"""
def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex def to_python(self, value):
"""
路由匹配时,匹配成功后传递给视图函数中参数的值
"""
return int(value) def to_url(self, value):
"""
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
"""
val = super(RegexConverter, self).to_url(value)
return val
# 添加到flask中
app.url_map.converters['regex'] = RegexConverter
@app.route('/index/<regex("\d+"):nid>')
def index(nid):
print(url_for('index', nid='888'))
return 'Index' if __name__ == '__main__':
app.run()

5.模板

比django中多可以加括号,执行函数,传参数

from flask import Flask,render_template,Markup,jsonify,make_response
app = Flask(__name__) def func1(arg):
return Markup("<input type='text' value='%s' />" %(arg,))
@app.route('/')
def index():
return render_template('index.html',ff = func1) if __name__ == '__main__':
app.run()

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> {{ff('六五')}}
{{ff('六五')|safe}} </body>
</html>

注意:

1.Markup等价django的mark_safe ,

2.extends,include一模一样

6.请求响应

   from flask import Flask
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response app = Flask(__name__) @app.route('/login.html', methods=['GET', "POST"])
def login(): # 请求相关信息
# request.method
# request.args
# request.form
# request.values
# request.cookies
# request.headers
# request.path
# request.full_path
# request.script_root
# request.url
# request.base_url
# request.url_root
# request.host_url
# request.host
# request.files
# obj = request.files['the_file_name']
# obj.save('/var/www/uploads/' + secure_filename(f.filename)) # 响应相关信息
# return "字符串"
# return render_template('html模板路径',**{})
# return redirect('/index.html')
#return jsonify({'k1':'v1'}) # response = make_response(render_template('index.html'))
# response是flask.wrappers.Response类型
# response.delete_cookie('key')
# response.set_cookie('key', 'value')
# response.headers['X-Something'] = 'A value'
# return response
return "内容" if __name__ == '__main__':
app.run()

7.session

除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。 (app.session_interface对象)

设置:session['username'] = 'xxx'
删除:session.pop('username', None)

8.闪现(message)

-设置:flash('aaa')
-取值:get_flashed_message()
-假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息

示例:

from flask import Flask,flash,get_flashed_messages,request,redirect

app = Flask(__name__)
app.secret_key = 'asdfasdf' @app.route('/index')
def index():
# 从某个地方获取设置过的所有值,并清除。
val = request.args.get('v')
if val == 'oldboy':
return 'Hello World!'
flash('超时错误',category="x1")
return "ssdsdsdfsd"
# return redirect('/error') @app.route('/error')
def error():
"""
展示错误信息
:return:
"""
data = get_flashed_messages(category_filter=['x1'])
if data:
msg = data[0]
else:
msg = "..."
return "错误信息:%s" %(msg,) if __name__ == '__main__':
app.run()

9.请求拓展

1 before_request

类比django中间件中process_request,在请求收到之前绑定一个函数做一些事情

#基于它做用户登录认证
@app.before_request
def process_request(*args,**kwargs):
if request.path == '/login':
return None
user = session.get('user_info')
if user:
return None
return redirect('/login')

2 after_request

类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常

@app.after_request
def process_response1(response):
print('process_response1 走了')
return response

3 teardown_request

每一个请求之后绑定一个函数,即使遇到了异常

@app.teardown_request
def ter(e):
pass

4 errorhandle

路径不存在时404,服务器内部错误500

@app.errorhandler(404)
def error_404(arg):
return "404错误了"

5 template_global

标签

@app.template_global()
def sb(a1, a2):
return a1 + a2
#{{sb(1,2)}}

6 template_filter

过滤器

@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
#{{ 1|db(2,3)}}

总结:

1 重点掌握before_request和after_request,

2 注意有多个的情况,执行顺序

3 before_request请求拦截后(也就是有return值),response所有都执行

10.蓝图

对程序进行目录结构划分

不使用蓝图,自己分文件

目录结构:

-templates
-views
-__init__.py
-user.py
-order.py
-app.py

app.py

from views import app
if __name__ == '__main__':
app.run()

init.py

from flask import Flask,request
app = Flask(__name__)
#不导入这个不行
from . import account
from . import order
from . import user

user.py

from . import app
@app.route('/user')
def user():
return 'user'

order.py

from . import app
@app.route('/order')
def order():
return 'order'

11.g对象

专门用来存储用户信息的g对象,g的全称的为global

g对象在一次请求中的所有的代码的地方,都是可以使用的

g对象和session的区别

session对象是可以跨request的,只要session还未失效,不同的request的请求会获取到同一个session,但是g对象不是,g对象不需要管过期时间,请求一次就g对象就改变了一次,或者重新赋值了一次

12.flask-session

作用:将默认保存的签名cookie中的值 保存到 redis/memcached/file/Mongodb/SQLAlchemy

安装:pip3 install flask-session

使用1:

from flask import Flask,session
from flask_session import RedisSessionInterface
import redis
app = Flask(__name__)
conn=redis.Redis(host='127.0.0.1',port=6379)
#use_signer是否对key签名
app.session_interface=RedisSessionInterface(conn,key_prefix='lqz')
@app.route('/')
def hello_world():
session['name']='lqz'
return 'Hello World!' if __name__ == '__main__':
app.run()

使用2:

from redis import Redis
from flask.ext.session import Session
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='192.168.0.94',port='')
Session(app)

问题:设置cookie时,如何设定关闭浏览器则cookie失效。

response.set_cookie('k','v',exipre=None)#这样设置即可
#在session中设置
app.session_interface=RedisSessionInterface(conn,key_prefix='lqz',permanent=False)
#一般不用,我们一般都设置超时时间,多长时间后失效

问题:cookie默认超时时间是多少?如何设置超时时间

#源码expires = self.get_expiration_time(app, session)
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),#这个配置文件控制

13.wtforms

安装:pip3 install wtforms

使用1:

from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets app = Flask(__name__, template_folder='templates') app.debug = True class LoginForm(Form):
# 字段(内部包含正则表达式)
name = simple.StringField(
label='用户名',
validators=[
validators.DataRequired(message='用户名不能为空.'),
validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
],
widget=widgets.TextInput(), # 页面上显示的插件
render_kw={'class': 'form-control'} )
# 字段(内部包含正则表达式)
pwd = simple.PasswordField(
label='密码',
validators=[
validators.DataRequired(message='密码不能为空.'),
validators.Length(min=8, message='用户名长度必须大于%(min)d'),
validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符') ],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
) @app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
form = LoginForm()
return render_template('login.html', form=form)
else:
form = LoginForm(formdata=request.form)
if form.validate():
print('用户提交数据通过格式验证,提交的值为:', form.data)
else:
print(form.errors)
return render_template('login.html', form=form) if __name__ == '__main__':
app.run()

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录</h1>
<form method="post">
<p>{{form.name.label}} {{form.name}} {{form.name.errors[0] }}</p> <p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0] }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>

使用2:

from flask import Flask, render_template, request, redirect
from wtforms import Form
from wtforms.fields import core
from wtforms.fields import html5
from wtforms.fields import simple
from wtforms import validators
from wtforms import widgets app = Flask(__name__, template_folder='templates')
app.debug = True class RegisterForm(Form):
name = simple.StringField(
label='用户名',
validators=[
validators.DataRequired()
],
widget=widgets.TextInput(),
render_kw={'class': 'form-control'},
default='alex'
) pwd = simple.PasswordField(
label='密码',
validators=[
validators.DataRequired(message='密码不能为空.')
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
) pwd_confirm = simple.PasswordField(
label='重复密码',
validators=[
validators.DataRequired(message='重复密码不能为空.'),
validators.EqualTo('pwd', message="两次密码输入不一致")
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
) email = html5.EmailField(
label='邮箱',
validators=[
validators.DataRequired(message='邮箱不能为空.'),
validators.Email(message='邮箱格式错误')
],
widget=widgets.TextInput(input_type='email'),
render_kw={'class': 'form-control'}
) gender = core.RadioField(
label='性别',
choices=(
(1, '男'),
(2, '女'),
),
coerce=int # “1” “2”
)
city = core.SelectField(
label='城市',
choices=(
('bj', '北京'),
('sh', '上海'),
)
) hobby = core.SelectMultipleField(
label='爱好',
choices=(
(1, '篮球'),
(2, '足球'),
),
coerce=int
) favor = core.SelectMultipleField(
label='喜好',
choices=(
(1, '篮球'),
(2, '足球'),
),
widget=widgets.ListWidget(prefix_label=False),
option_widget=widgets.CheckboxInput(),
coerce=int,
default=[1, 2]
) def __init__(self, *args, **kwargs):
super(RegisterForm, self).__init__(*args, **kwargs)
self.favor.choices = ((1, '篮球'), (2, '足球'), (3, '羽毛球')) def validate_pwd_confirm(self, field):
"""
自定义pwd_confirm字段规则,例:与pwd字段是否一致
:param field:
:return:
"""
# 最开始初始化时,self.data中已经有所有的值 if field.data != self.data['pwd']:
# raise validators.ValidationError("密码不一致") # 继续后续验证
raise validators.StopValidation("密码不一致") # 不再继续后续验证 @app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
form = RegisterForm(data={'gender': 2,'hobby':[1,]}) # initial
return render_template('register.html', form=form)
else:
form = RegisterForm(formdata=request.form)
if form.validate():
print('用户提交数据通过格式验证,提交的值为:', form.data)
else:
print(form.errors)
return render_template('register.html', form=form) if __name__ == '__main__':
app.run()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户注册</h1>
<form method="post" novalidate style="padding:0 50px">
{% for field in form %}
<p>{{field.label}}: {{field}} {{field.errors[0] }}</p>
{% endfor %}
<input type="submit" value="提交">
</form>
</body>
</html>

14.信号

Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为

安装:pip3 install blinker

内置信号:

request_started = _signals.signal('request-started')                # 请求到来前执行
request_finished = _signals.signal('request-finished') # 请求结束后执行 before_render_template = _signals.signal('before-render-template') # 模板渲染前执行
template_rendered = _signals.signal('template-rendered') # 模板渲染后执行 got_request_exception = _signals.signal('got-request-exception') # 请求执行出现异常时执行 request_tearing_down = _signals.signal('request-tearing-down') # 请求执行完毕后自动执行(无论成功与否)
appcontext_tearing_down = _signals.signal('appcontext-tearing-down')# 应用上下文执行完毕后自动执行(无论成功与否) appcontext_pushed = _signals.signal('appcontext-pushed') # 应用上下文push时执行
appcontext_popped = _signals.signal('appcontext-popped') # 应用上下文pop时执行
message_flashed = _signals.signal('message-flashed') # 调用flask在其中添加数据时,自动触发

使用信号:

from flask import Flask,signals,render_template

app = Flask(__name__)

# 往信号中注册函数
def func(*args,**kwargs):
print('触发型号',args,kwargs)
signals.request_started.connect(func) # 触发信号: signals.request_started.send()
@app.before_first_request
def before_first1(*args,**kwargs):
pass
@app.before_first_request
def before_first2(*args,**kwargs):
pass @app.before_request
def before_first3(*args,**kwargs):
pass @app.route('/',methods=['GET',"POST"])
def index():
print('视图')
return render_template('index.html') if __name__ == '__main__':
app.wsgi_app
app.run()

一个流程中的信号触发点(了解)

a. before_first_request
b. 触发 request_started 信号
c. before_request
d. 模板渲染
渲染前的信号 before_render_template.send(app, template=template, context=context)
rv = template.render(context) # 模板渲染
渲染后的信号 template_rendered.send(app, template=template, context=context)
e. after_request
f. session.save_session()
g. 触发 request_finished信号
如果上述过程出错:
触发错误处理信号 got_request_exception.send(self, exception=e) h. 触发信号 request_tearing_down

自定义信号(了解):

from flask import Flask, current_app, flash, render_template
from flask.signals import _signals
app = Flask(import_name=__name__) # 自定义信号
xxxxx = _signals.signal('xxxxx') def func(sender, *args, **kwargs):
print(sender)
# 自定义信号中注册函数
xxxxx.connect(func)
@app.route("/x")
def index():
# 触发信号
xxxxx.send('', k1='v1')
return 'Index' if __name__ == '__main__':
app.run()

15.多app应用

from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
from flask import Flask, current_app
app1 = Flask('app01')
app2 = Flask('app02') @app1.route('/index')
def index():
return "app01" @app2.route('/index2')
def index2():
return "app2" # http://www.oldboyedu.com/index
# http://www.oldboyedu.com/sec/index2
dm = DispatcherMiddleware(app1, {
'/sec': app2,
}) if __name__ == "__main__":
run_simple('localhost', 5000, dm)

16.flask-script

用于实现类似于django中 python3 manage.py runserver ...类似的命令

安装:pip3 install flask-script

使用

from flask_script import Manager
app = Flask(__name__)
manager=Manager(app)
...
if __name__ == '__main__':
manager.run()
#以后在执行,直接:python3 manage.py runserver
#python3 manage.py runserver --help

JQ高级的更多相关文章

  1. Linux服务器性能压力测试

    对于新采购的服务器,需要进行有必要的性能测试.这里选择UnixBench工具进行性能测试.记录如下: 1)安装使用下面的脚本使用了最新版UnixBench5.1.3来测试,注释了关于graphic的测 ...

  2. day58

    JQ高级 一.选择器 1.css语法匹配 标签 | 类 | id | 交集 群组 | 后代 | 兄弟 伪类 | 属性 2.索引匹配 :eq(index) | :gt(index) | :lt(inde ...

  3. jquery基础知识2

    1.js和jquery对象的转换 js==>jquery对象 $(js对象) jquery==>js jq对象[index] jq对象.get(index) <!DOCTYPE ht ...

  4. JavaScript高级 面向对象(10)--onload与jq中ready的区别

    说明(2017.4.2): 1. 在body中放一个img标签,src链接一张图片,那么页面会先读取html的document文档,然后再读取外部资源(这里没加onload其实就是从上往下顺序读取). ...

  5. JQ写简单的伸缩菜单(内附效果图和源代码)

    效果如图: JQ代码就那么几句, <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "h ...

  6. 常用jq选择器和遍历的使用

    1.jq的选择器,常用有哪些? class id > ~ ul li a 2.遍历的使用(在使用用遍历节点时,我们的注意遍历在不传递参数(也就是传参),代表的是传递局部全局,也就是"* ...

  7. jq模糊匹配

    jq是一般程序员在前台开发的时候都会使用的技术,其中模糊匹配查询在动态添加标签的时候经常用到,这里我写出我经常用到的几个模糊匹配的方法.其中有:^(前缀).$(后缀).*(包含)例如有这样一段代码: ...

  8. 【jQuery】 JQ和AJAX

    AJAX AJAX全称异步 JavaScript 和 XML(Asynchronous JavaScript and XML),是一种用于网页前端和网站后台进行数据交互的手段.关于AJAX的详细介绍在 ...

  9. JQ初级

    一.认识jQuery 1.什么是jQuery jQuery是对原生JavaScript二次封装的工具函数集合 jQuery是一个简洁高效的且功能丰富的JavaScript工具库 2.jQuery的优势 ...

随机推荐

  1. C# 因缺少CategoryName,而未能初始化 的解决办法

    群里一小伙伴在开发APP时遇到了问题,便截图提问 一.傻瓜式解决办法: 删除: ((System.ComponentModel.ISupportInitialize)(this.performance ...

  2. flex-手机端主页布局实例---构造页面结构

    Flexbox页面布局实例,成本效果图如下, 源码下载在最下面. 源码下载:https://pan.baidu.com/s/18o5hVuWtflUpgvMk3LzQ5w  提取码:wiyc样本地址: ...

  3. php中读取中文文件夹及文件报错

    php读取时出现中文乱码 一般php输出中出现中文乱码我们可用 header ('content:text/html;charset="utf-8"'); php中读取中文文件夹及 ...

  4. Dart语言入门(一)

    Dart 语言介绍 Dart 是谷歌在 2011 年推出的编程语言,是一种结构化 Web 编程语言,允许用户通过 Chromium 中所整合的虚拟机(Dart VM)直接运行 Dart 语言编写的程序 ...

  5. .NET Core 学习笔记2——管理nuget包

    .NET Core 基于Nuget包.它是一个.nupkg后缀的zip文件. 工具 dotnet 工具 vs2017 的程序包管理控台 这两个工具都可以用命令行来下载安装,更新,上传包(上传要先在网站 ...

  6. MyDAL - .UpdateAsync() 之 .SetSegment 根据条件 动态设置 要更新的字段 使用

    索引: 目录索引 一.API 列表 1.SetSegment 属性,指示 根据条件 动态拼接 要修改的字段 见如下示例. 二.API 单表-完整 方法 举例 // update 要赋值的变量 var ...

  7. C#多线程和线程池 【转】

    1.概念  1.0 线程的和进程的关系以及优缺点 windows系统是一个多线程的操作系统.一个程序至少有一个进程,一个进程至少有一个线程.进程是线程的容器,一个C#客户端程序开始于一个单独的线程,C ...

  8. Jenkins实现简单的CI功能

    步骤一:安装JDK.Tomcat,小儿科的东西不在此详细描述 步骤二:下载安装Jenkins下载链接:https://jenkins.io/download/ 步骤三:将下载的jenkins.war部 ...

  9. 【P2577】 午餐

    题目简述 THU ACM小组一行N个人去食堂吃饭,计划是这样的:先把所有的人分成两队,并安排好每队中各人的排列顺序,然后一号队伍到一号窗口去排队打饭,二号队伍到二号窗口去排队打饭.每个人打完饭后立刻开 ...

  10. App Inventor2项目部署到本地

    介绍App Inventor App Inventor 原是Google实验室(Google Lab)的一个子计划,该项目是一个完全在线开发的Android编程环境,抛弃复杂的程式代码而使用积木式的堆 ...