2019-1-7 17:59:37
还有两天左右flask就结束啦!昨晚逛了一下吾爱破解还有慕课,发现有三个意外项目,
Django生鲜项目,flask电影网站项目,vue美团网项目,都保存百度云啦,寒假可以搞事情啦
还有十天左右的视频,看完后认证整理博客,然后争取整理本书,到时候回学校打印,233333333!
想想都是很有成就感的一件事情!
越努力,越幸运!永远不要高估自己!
今天讲了wtfroms 组件,就是Django中的form modelsForm 类似!
书上介绍的组件很多,flask那本书!
flask参考链接: https://www.cnblogs.com/wupeiqi/articles/8202357.html
还讲了 重要的东西 localproxy
这是关于localproxy的一个demo
s1.py
# by luffycity.com DATA = {
'request':{
'method':"GET",
'form':{}
},
'session':{
'user':'alex',
'age':""
}
} class LocalProxy(object):
def __init__(self,key):
self.key = key
def get_dict(self):
return DATA[self.key] def __str__(self):
return 'asdf' def __getattr__(self, item):
data_dict = self.get_dict()
return data_dict[item] def __getitem__(self, item):
data_dict = self.get_dict()
return data_dict[item] def __add__(self, other):
return other + 1 request = LocalProxy('request')
session = LocalProxy('session')
s2.py
from s2 import request,session print(request.method)
print(request.form) print(session.user)
print(session.age)
这是在flask中实现上下文管理 resquest 和session 的方法
from flask import Flask,request,session app = Flask(__name__) @app.route('/index')
def index():
# 1. request是LocalProxy对象
# 2. 对象中有method、执行__getattr__
print(request.method)
# request['method']
# request + 1 # 1. session是LocalProxy对象
# 2. LocalProxy对象的__setitem__
session['x'] = 123 return "Index" if __name__ == '__main__':
app.run()
# app.__call__
# app.wsgi_app """
第一阶段:请求到来
将request和Session相关数据封装到ctx=RequestContext对象中。
再通过LocalStack将ctx添加到Local中。
__storage__ = {
1231:{'stack':[ctx(request,session)]}
}
第二阶段:视图函数中获取request或session
方式一:直接找LocalStack获取
from flask.globals import _request_ctx_stack
print(_request_ctx_stack.top.request.method) 方式二:通过代理LocalProxy(小东北)获取
from flask import Flask,request
print(request.method) """
这是很重要的一张图,搞懂这个图就清楚 reqeust session g 和app 的上下文管理用法啦
wtforms基本使用
贴上源码
from flask import Flask,request,render_template,session,current_app,g,redirect
from wtforms import Form
from wtforms.fields import simple
from wtforms.fields import html5
from wtforms.fields import core from wtforms import widgets
from wtforms import validators app = Flask(__name__) class LoginForm(Form):
name = simple.StringField(
validators=[
validators.DataRequired(message='用户名不能为空.'),
# validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
],
widget=widgets.TextInput(),
render_kw={'placeholder':'请输入用户名'}
)
pwd = simple.PasswordField(
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个特殊字符') ],
render_kw={'placeholder':'请输入密码'}
) @app.route('/login',methods=['GET','POST'])
def login():
if request.method == "GET":
form = LoginForm()
# print(form.name,type(form.name)) # form.name是StringField()对象, StringField().__str__
# print(form.pwd,type(form.pwd)) # form.pwd是PasswordField()对象,PasswordField().__str__
return render_template('login.html',form=form) form = LoginForm(formdata=request.form)
if form.validate():
print(form.data)
return redirect('https://www.luffycity.com/home')
else:
# print(form.errors)
return render_template('login.html', form=form) 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 # int("1")
)
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, ]
) @app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
form = RegisterForm()
return render_template('register.html', form=form) form = RegisterForm(formdata=request.form)
if form.validate():
print(form.data)
return redirect('https://www.luffycity.com/home') return render_template('register.html', form=form) import helper
class UserForm(Form):
city = core.SelectField(
label='城市',
choices=(),
coerce=int
)
name = simple.StringField(label='姓名') # 为了解决数据库修改信息未能在页面刷新,
# 解决方法: 就是直接在视图函数中先父类初始化和查找一下该字段的值
def __init__(self,*args,**kwargs):
super(UserForm,self).__init__(*args,**kwargs) self.city.choices=helper.fetch_all('select id,name from tb1',[],type=None) @app.route('/user')
def user():
if request.method == "GET":
#form = UserForm(data={'name':'alex','city':3})
form = UserForm()
return render_template('user.html',form=form) if __name__ == '__main__':
app.run()
连接数据库用的连接池
helper.py
import pymysql
from DBUtils.PooledDB import PooledDB, SharedDBConnection
import pymysql POOL = PooledDB(
creator=pymysql, # 使用链接数据库的模块
maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=5, # 链接池中最多闲置的链接,0和None不限制
maxshared=3,
# 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。
blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]
ping=0,
# ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
host='127.0.0.1',
port=3306,
user='root',
password='',
database='s9day119',
charset='utf8'
) def connect(type):
conn = POOL.connection()
cursor = conn.cursor(cursor=type)
return conn,cursor def connect_close(conn,cursor):
cursor.close()
conn.close() def fetch_all(sql,args,type=pymysql.cursors.DictCursor):
conn,cursor = connect(type) cursor.execute(sql, args)
record_list = cursor.fetchall()
connect_close(conn,cursor) return record_list def fetch_one(sql, args):
conn, cursor = connect()
cursor.execute(sql, args)
result = cursor.fetchone()
connect_close(conn, cursor) return result def insert(sql, args):
conn, cursor = connect()
row = cursor.execute(sql, args)
conn.commit()
connect_close(conn, cursor)
return row
login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form method="post" novalidate>
<p>用户名:{{form.name}} {{form.name.errors[0]}}</p>
<p>密码:{{form.pwd}} {{form.pwd.errors[0]}} </p>
<p><input type="submit" value="提交" ></p>
</form>
</body>
</html>
register.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form method="post" novalidate> {% for field in form %}
<p>{{field.label}}: {{field}} {{field.errors[0]}}</p>
{% endfor %} <input type="submit" value="提交">
</form>
</body>
</html>
user.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form method="post">
{% for field in form %}
<p>{{field.label}}: {{field}} {{field.errors[0]}}</p>
{% endfor %}
<input type="submit" value="提交">
</form>
</body>
</html>
贴上笔记:
s9day119 内容回顾:
第一部分:Flask
1. 谈谈你对django和flask的认识? 2. Flask基础:
- 配置文件:反射+importlib
- 路由系统:
- 装饰器 @app.route()
- 参数:
- url
- endpoint
- methods
- 加装饰器
- endpoint默认是函数名
- functools.wraps(func) + functools.partial
- 写路由两种方式:
- 装饰器
- add_url_rule
- 自定义支持正则的URL
- session
- 蓝图
- 目录结构划分
- 前缀
- 特殊装饰器
3. 上下文管理
- threading.local
- 为每个线程开辟空间,使得线程之间进行数据隔离。
- 应用:DBUtils中为每个线程创建一个数据库连接时使用。
- 面向对象特殊方法:
- getattr
- setattr
- delattr
- 偏函数
- 单例模式
- 请求上下文流程:
- 班级示例:
- 源码流程:
- __call__
- wsgi_app
- ctx = RequestContext(): 封装= 请求数据+空session
- ctx.push() : 将ctx传给LocalStack对象,LocalStack再将数据传给Local存储起来。
问题:Local中是如何存储?
__storage__ = {
1231:{}
}
问题:LocalStack作用?
__storage__ = {
1231:{stack:[ctx] }
}
- 视图函数:再次去获取
- 关闭 4. 第三方组件:
1. flask-session
2. DBUtils 第二部分:数据库&前端
1. 什么是响应式布局?
@media属性
2. MySQL数据库
- 引擎:
- innodb
- 支持事务
- 锁
- 行锁
- 表锁
- 示例:
- 终端:
begin;
select xx from xx for update;
commit;
- pymysql
cursor.execute('select * from xx for update')
- django
with trancation.automic():
models.User.objects.all().for_update()
- mysaim
- 不支持事务
- 锁
- 表锁
- 快 今日内容:
1. 上下文管理:LocalProxy对象
2. 上下文管理:
- 请求上下文:request/session
- App上下文: app/g
3. 第三方组件:wtforms
作用:
- 生成HTML标签
- form表单验证
安装:
pip3 install wtforms 使用:
- 用户登录
- 用户注册
- 从数据库获取数据 内容详细:
1. 上下文管理:LocalProxy对象
2. 上下文管理:
- 请求上下文(ctx=RequestContext()):request/session
- App上下文(app_ctx=AppContext()): app/g - 程序启动:
两个Local:
local1 = { } local2 = { } 两个LocalStack:
_request_ctx_stack
_app_ctx_stack
- 请求到来
对数据进行封装:
ctx = RequestContext(request,session)
app_ctx = AppContext(app,g)
保存数据:
将包含了(app,g)数据的app_ctx对象,利用 _app_ctx_stack(贝贝,LocalStack())将app_ctx添加到Local中
storage = {
1231:{stack:[app_ctx(app,g),]}
}
将包含了request,session数据的ctx对象,利用_request_ctx_stack(刘淞,LocalStack()),将ctx添加到Local中
storage = {
1231:{stack:[ctx(request,session),]}
} - 视图函数处理: from flask import Flask,request,session,current_app,g app = Flask(__name__) @app.route('/index')
def index():
# 去请求上下文中获取值 _request_ctx_stack
request.method # 找小东北获取值
session['xxx'] # 找龙泰获取值 # 去app上下文中获取值:_app_ctx_stack
print(current_app)
print(g) return "Index" if __name__ == '__main__':
app.run()
app.wsgi_app - 结束
_app_ctx_stack.pop()
_request_ctx_stack.pop() 问题:
1. Flask中g的生命周期?
2. g和session一样吗?
3. g和全局变量一样吗?