1 flask-session
两种方式:
1. 指定session类接口:自定义session类 或者 flask-session的 RedisSessionInterface
2. 第三方session库: flask-session 配置 (通用方案)
conn = redis.Redis()
app.session_interface = RedisSessionInterface(conn, 'lqz' )
通用方案:flask集成第三方库的通用方案 基本也是实例化第三方的类,再包装下Flask对象
from flask_session import Session
app.config['SESSION_TYPE' ] = 'redis'
app.config['SESSION_KEY_PREFIX' ] = 'lqz'
app.config['SESSION_REDIS' ] = redis.Redis()
Session(app)
app.config['PERMANENT_SESSION_LIFETIME' ]=timedelta(seconds=7 )
-save_session
-open_session
2 数据库连接池dbutils
-随着并发量的越来越大,mysql的连接数也会增大
-我们创建出连接池后,每次从池中获取连接使用,能够避免并发量过大,导致数据库崩掉的危险
DBUtils是Python的一个用于实现数据库连接池的模块
import pymysql
from dbutils.pooled_db import PooledDB
POOL = PooledDB(
creator=pymysql,
maxconnections=6 ,
mincached=2 ,
maxcached=5 ,
maxshared=3 ,
blocking=True ,
maxusage=None ,
setsession=[],
ping=0 ,
host='127.0.0.1' ,
port=3306 ,
user='root' ,
password='111' ,
database='cnblogs' ,
charset='utf8'
)
def func ():
conn = POOL.connection()
cursor = conn.cursor()
cursor.execute('select * from user' )
result = cursor.fetchall()
print (result)
conn.close()
if __name__ == '__main__' :
func()
3 wtfroms(了解)
3.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__)
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()
<!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 >
3.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='egon'
)
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:
"""
if field.data != self.data['pwd' ]:
raise validators.StopValidation("密码不一致" )
@app.route('/register' , methods=['GET' , 'POST' ] )
def register ():
if request.method == 'GET' :
form = RegisterForm(data={'gender' : 2 ,'hobby' :[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()
<!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 >
4 信号(重要)
在视图任务的某些关键位置,绑定上信号函数,视图任务运行到该位置时,会触发执行
eg: 数据库新增成功后,都记录一条日志
原方法:需要在视图里每个操作完数据库之后,手动记录日志
使用信号:只需要定义一个函数,信号在关键位置,都可以记录日志
信号 和 并发编程中 信号量 不是同一个东西!!!
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' )
appcontext_popped = _signals.signal('appcontext-popped' )
message_flashed = _signals.signal('message-flashed' )
4.1 内置信号使用
模板渲染后信号执行
功能:home页面被渲染后,记录一条日志
from flask import signals
def template_test (*args,**kwargs ):
print (args)
print (kwargs)
print ('模板渲染完了' )
signals.template_rendered.connect(template_test)
4.2 自定义信号
from flask import signals
xxxxx = signals._signals.signal('xxxxx' )
def xxx_test (*args, **kwargs ):
print (args)
print (kwargs)
print ('xxx信号触发了' )
xxxxx.connect(xxx_test)
@app.route('/' )
def index ():
xxxxx.send('123123' , k1='v1' )
return 'hello'
5 flask-script 自定义命令
pip3 install flask-script
-自带一个runserver 命令
-支持自定制命令
-eg:
启动celery: 脚本文件里:使用subprocess('系统cmd或shell命令' ) 执行系统命令
清空某个表的所有记录
自动发布项目
-作用:自己写了一些 比如项目准备的小脚本,eg: 创建库、数据库测试数据等函数
然后用 自定制命令的形式 执行脚本
python manage.py 命令函数 参数
把excel的数据导入数据库 定制个命令 去执行
详见:https://pythondjango.cn/django/advanced/11 -django-admin-commands/
app01/
__init__.py
models.py
management/
__init__.py
commands/
__init__.py
_private.py
initdb.py
tests.py
views.py
1. 在app内创建一个management的包
2. 在management目录里面创建commands的包
3. 在commands文件夹下创建任意py文件
4. 命令文件内部
from django.core.management.base import BaseCommand
class Command (BaseCommand ):
help = 'Some help texts'
def add_arguments (self, parser ):
pass
def handle (self, *args, **options ):
pass
python manage.py initdb xx.xsl article
5.1 基本使用
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
@app.route('/' )
def index ():
return 'hello'
if __name__ == '__main__' :
manager.run()
python 文件名 runserver
就变成 python manage.py runserver
5.2 自定义命令
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
@manager.command
def custom (arg ):
"""
自定义命令:python manage.py custom 123
"""
print (arg)
@manager.option('-n' , '--name' , dest='name' )
@manager.option('-u' , '--url' , dest='url' )
def cmd (name, url ):
"""
自定义命令(-n也可以写成--name)
执行: python manage.py cmd -n lqz -u http://www.oldboyedu.com
执行: python manage.py cmd --name lqz --url http://www.oldboyedu.com
"""
print (name, url)
if __name__ == '__main__' :
manager.run()
6 flask_sqlalchemy使用
采用scoped_session() ,全部导入sqlalchemy模板 来直接书写
采用第三方模块 flask_sqlalchemy
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:@127.0.0.1:3306/db1?charset=utf8"
SQLALCHEMY_POOL_SIZE = 5
SQLALCHEMY_POOL_TIMEOUT = 30
SQLALCHEMY_POOL_RECYCLE = -1
SQLALCHEMY_TRACK_MODIFICATIONS = False
1. 导入from flask_sqlalchemy import SQLAlchemy
2. 实例化得到db对象
db = SQLALchemy()
3. 在app中注册
db.init_app(app)
4. 表模型继承 db.Model
5. session是db.session
db.session使用即可
1 表迁移麻烦
2 不支持字段的动态修改
7 flask-migrate使用
pip install flask-migrate
1. 导入
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
2. 执行
manager = Manager(app)
Migrate(app, db)
manager.add_command('db' , MigrateCommand)
3. 命令行执行命令
python manage.py db init
python manage.py db migrate
python manage.py db upgrade
在migrations-->versions目录里面,有一个xx.py,它记录的models.py的修改
那么它和django也是同样,有一个文件记录变化
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!