上一篇文章
>Flask入门(二)之偏函数、数据库连接池(DBUtils)
Flask中默认不支持信号,需要我们安装第三方插件!!!
下载地址:https://pypi.org/project/blinker/#files
[root@Python ~]# wget https://files.pythonhosted.org/packages/1b/51/e2a9f3b757eb802f61dc1f2b09c8c99f6eb01cf06416c0671253536517b6/blinker-1.4.tar.gz
[root@Python ~]# tar xf blinker-1.4.tar.gz
[root@Python ~]# cd blinker-1.4/
[root@Python blinker-1.4]# python setup.py install
测试:
[root@Python ~]# python
Python 3.6.0 (default, Jun 17 2019, 16:17:21)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import 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
app = Flask(__name__)
### 往信号中注册函数
def fun(*args, **kwargs):
print ('触发信号',args,kwargs)
### 触发信号:singnals.request_start.send()
signals.request_started.connect(fun)
@app.route('/', methods=['GET','POST'])
def index():
print ('view')
return 'index'
if __name__ == "__main__":
app.run()
1. before_first_request
2. 触发request_started信号
3. before_request
4. 模板渲染
渲染前的信号before_render_template.send(app,template=template, context=context)
rv = template.render(context) ###模板渲染
渲染后的信号template_rendered_send(app,template=template, context=context)
5. after_request
6. session.save_session()
7. 触发request_finished信号
如果上述过程出错:
触发错误处理信号got_request_exception.send(self,exception=e)
8. 触发信号request_tearing_down
MetaClass作用:用来指定当前类由谁来创建(默认type创建)
class Foo(object):
__metaclass__ = type
pass
class Foo(metaclass=type):
pass
class MyType(type):
def __init__(self,*args,**kwargs):
print ("init")
super(MyType,self).__init__(*args,**kwargs)
### call本质:调用类的__new__,再调用类的__init__
def __call__(self, *args, **kwargs):
print ('call')
class Foo(metaclass=MyType):
pass
class Bar(Foo):
pass
obj = Bar()
运行结果:
init
init
call
type可以创建类metaclass=type;MyType也可以创建类metaclass=MyType
class MyType(type):
def __init__(self,*args,**kwargs):
super(MyType,self).__init__(*args,**kwargs)
### call本质:调用类的__new__,再调用类的__init__
def __call__(cls, *args, **kwargs):
return super(MyType, cls).__call__(*args, **kwargs)
### Base = MyType('Base',(object,),{})
### MyType('Base',(object,),{})是由MyType创建;metaclass=MyType
class Foo(MyType('Base',(object,), {})):
pass
obj = Foo()
class MyType(type):
def __init__(self,*args,**kwargs):
super(MyType,self).__init__(*args,**kwargs)
def __call__(cls, *args, **kwargs):
return super(MyType, cls).__call__(*args, **kwargs)
def with_metaclass(base):
return MyType('xx',(base,), {})
class Foo(with_metaclass(object)):
pass
obj = Foo()
内置将session保存在加密cookie中实现
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
{
'DEBUG': get_debug_flag(default=False), 是否开启Debug模式
'TESTING': False, 是否开启测试模式
'PROPAGATE_EXCEPTIONS': None,
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': timedelta(days=31),
'USE_X_SENDFILE': False,
'LOGGER_NAME': None,
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None,
'APPLICATION_ROOT': None,
'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12),
'TRAP_BAD_REQUEST_ERRORS': False,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None,
}
import os
from flask import Flask,session
app = Flask(__name__)
app.secret_key = os.urandom(24)
@app.route('/')
def index():
### 执行session对象的__setitem__方法
session['xxx'] = 123
return 'Index'
if __name__ == "__main__":
app.run(host='10.10.10.111')
下载地址:https://pypi.org/project/Flask-Session/#files
[root@Python ~]# wget https://files.pythonhosted.org/packages/2e/9f/b138521d0416b001469bcdc79a3619f013c0563204f7251ba978eb3e69d5/Flask-Session-0.3.1.tar.gz
[root@Python ~]# tar xf Flask-Session-0.3.1.tar.gz
[root@Python ~]# cd Flask-Session-0.3.1/
[root@Python Flask-Session-0.3.1]# python setup.py install
<1> reidis-server安装
[root@python ~]# wget http://download.redis.io/releases/redis-4.0.8.tar.gz
[root@python ~]# yum install -y gcc
[root@python ~]# tar xf redis-4.0.8.tar.gz
[root@python redis-4.0.8]# cd redis-4.0.8
[root@python redis-4.0.8]# make && make install
[root@python redis-4.0.8]# cd utils/
[root@python utils]# ./install_server.sh ###一直按回车即可
### 查看是否有端口
[root@python ~]# netstat -lntup|grep redis
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 979/redis-server 12
[root@Python ~]# vim /etc/redis/6379.conf
[root@Python ~]# /etc/init.d/redis_6379 restart
[root@python ~]# wget https://files.pythonhosted.org/packages/4a/1b/9b40393630954b54a4182ca65a9cf80b41803108fcae435ffd6af57af5ae/redis-3.0.1.tar.gz
[root@python ~]# tar xf redis-3.0.1.tar.gz
[root@python ~]# cd redis-3.0.1/
[root@python redis-3.0.1]# python setup.py install
import os
from flask import Flask, session
from flask_session import RedisSessionInterface
from redis import Redis
app = Flask(__name__)
app.secret_key = os.urandom(24)
conn = Redis(host='10.10.10.111')
app.session_interface = RedisSessionInterface(conn, key_prefix='__', use_signer=False)
@app.route('/')
def index():
session['xxx'] = 123
return 'Index'
if __name__ == "__main__":
app.run(host='10.10.10.111')
import os
from flask import Flask, session
from redis import Redis
from flask_session import Session
app = Flask(__name__)
app.secret_key = os.urandom(24)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = Redis(host='10.10.10.111')
Session(app)
@app.route('/')
def index():
session['xxx'] = 123
return 'Index'
if __name__ == "__main__":
app.run(host='10.10.10.111')
下载地址:https://pypi.org/project/WTForms/#files
[root@Python ~]# wget https://files.pythonhosted.org/packages/cd/1d/7221354ebfc32b868740d02e44225c2ce00769b0d3dc370e463e2bc4b446/WTForms-2.2.1.tar.gz
[root@Python ~]# tar xf WTForms-2.2.1.tar.gz
[root@Python ~]# cd WTForms-2.2.1/
[root@Python WTForms-2.2.1]# python setup.py install
[root@Python wtforms]# tree
.
├── app.py
└── templates
└── login.html
[root@Python wtforms]# vim app.py
#!/usr/bin/env python
#coding:utf-8
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')
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个数字和一个特殊字符')
],
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(host='10.10.10.111')
[root@Python wtforms]# mkdir templates/
[root@Python wtforms]# vim templates/login.html
Title
登陆
[root@Python wtforms]# tree
.
├── app01.py
└── templates
└── register.html
[root@Python wtforms]# vim app01.py
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='Dream'
)
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
)
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': 1})
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(host='10.10.10.111')
[root@Python wtforms]# vim templates/register.html
Title
用户注册
下一篇文章
>Flask入门(四)之SQLAlchemy、Flask-SQLAlchemy、pipreqs、Flask-Script、Flask-Migrate