flask 之 wtforms
先把标题给列出来,我们的flask到了这个阶段就需要把我们的源码都吃透了,源码都需要去整理出来
在看wtform源码之前我们先把面向对象的一些知识点给补充一下

1 class A(): 2 ... 3 class B(A): 4 ... 5 class C(): 6 ... 7 class D(B,C): 8 ... 9 print(D.__mro__) # 深度优先

1 class HeType(type): 2 def __init__(self, *args, **kwargs): 3 super(HeType, self).__init__(*args, **kwargs) 4 print('hello') 5 6 7 class Fo(object, metaclass=HeType): 8 """ 9 Fo这个类是通过metaclass来选择我们自定义的HeType来创建的,而我们自定义的类又继承了Type类, 10 11 """ 12 ... 13 14 15 obj = Fo() 16 """ 17 0,先执行我们的HeType里面的__init__ 18 1,然后是HeType的__call__ 19 2,再来就是Fo的__new__ 20 3,最后是Fo的__init__ 21 """

1 class Fo(): 2 name='peter' 3 def __init__(self,name,age): 4 self.name=name 5 self.age=age 6 def func(self): 7 ... 8 9 print(1,Fo.__dict__) 10 """ 11 1 {'__module__': '__main__', 12 'name': 'peter', 13 '__init__': <function Fo.__init__ at 0x000000000252FAE8>, 14 'func': <function Fo.func at 0x000000000252FF28>, 15 '__dict__': <attribute '__dict__' of 'Fo' objects>, 16 '__weakref__': <attribute '__weakref__' of 'Fo' objects>, 17 '__doc__': None} 18 """ 19 print(2,dir(Fo)) 20 """ 21 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 22 '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', 23 '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', 24 '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 25 '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 26 'func', 'name'] 27 """

1 s8day127 2 3 内容回顾: 4 1. django/flask框架的认识? 5 6 2. Flask上下文管理机制 7 PS: 类 8 9 3. 为什么把请求放到RequestContext中: 10 ctx = RequestContext(request,session) 11 4. Local对象作用? 12 - 看过Local源码,threading.local相似,但是又有不同之处。 13 - Local中基于greenlet获取唯一标识,粒度更细。 14 5. LocalStack对象作用? 15 - 对Local对象中的数据进行操作。 16 - 将local对象中的数据维护成一个栈 17 local = { 18 1231:{stack: [ctx,]} 19 } 20 6. 上下文管理 21 请求上下文:request/session 22 App上下文: app/g 23 7. 什么是g? 24 25 8. 获取Session/g/current_app/request 26 27 9. 技术: 28 - 反射 29 - 面向对象,封装:RequestContext 30 __dict__ 31 - 线程(threading.local) 32 - 笔试:自己写一个类+列表 实现栈。(LocalStack,文杰) 33 34 PS: 一定要会 35 36 今日内容: 37 1. flask-session 38 39 2. 数据库连接池:DBUtils(pymysql) 40 41 3. wtforms 42 43 4. SQLAchemy/flask-sqlachemy 44 45 5. flask-script 46 47 6. flask-migrate 48 49 内容概要: 50 0. 补充:视频播放 51 52 1. flask-session 53 作用:将默认保存的签名cookie中的值 保存到 redis/memcached/file/Mongodb/SQLAlchemy 54 55 应用: 56 a. 配置 57 app.config['SESSION_TYPE'] = 'redis' 58 app.config['SESSION_REDIS'] = Redis(host='192.168.0.94',port='6379') 59 60 b. 替换 61 from flask_session import Session 62 Session(app) 63 64 注意:session中存储的是字典,修改字典内部元素时,会造成数据不更新。 65 - motified = True 66 - SESSION_REFRESH_EACH_REQUEST = True and session.permanent = True(redis中默认) 67 68 69 PS: 70 数据框 模板 视图 71 MTV, Model Template View 72 MVC, Model View Controller 73 74 2. 数据库连接池 75 pip install DBUtils 76 77 模式: 78 - 每个线程创建一个连接,关闭(默认不关闭),线程终止时,才关闭连接。 79 - 创建共享连接池 80 81 应用:只要写原生SQL,用户数据框连接池 82 83 84 85 3. wtforms 86 作用:用于对python web框架做表单验证。 87 88 使用: 89 class MyForm(Form): 90 user = 类(正则,插件) 91 字段 = 类(正则,插件) 92 字段 = 类(正则,插件) 93 字段 = 类(正则,插件) 94 字段 = 类(正则,插件) 95 字段 = 类(正则,插件) 96 97 98 form = MyForm() 99 # 生成HTML标签 100 print(form.user) 类.__str__ ==> 插件.xx方法 101 102 # 验证 103 form = MyForm(formdata=request.form) 104 if form.validate(): 105 # 内部找到所有的字段:user + 用户发过来的数据 =》 正则校验 106 107 基本使用: 108 http://www.cnblogs.com/wupeiqi/articles/8202357.html 109 110 111 112 总结: 113 1. 授权播放 114 2. flask-session 115 3. dbutils 116 4. wtforms 117 - 未完待续 118 119 作业: 120 - 上下文管理 121 - flask-session 122 - 路飞完成 123 124 - wtforms 125 - user = simple.StringField() 126 UnboundField(simple.StringField,计数器) 127 128 - FormMeta.__call__ 129 130 - 自己写类实现栈 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
这里是基于蓝图创建的flask项目
蓝图的创建步骤,
一个文件夹,然后在里面再创建一个文件夹,这两者要同名,
在最外层的文件夹里面创建一个manage文件,还有一个settings文件
在里面的这层同名的文件夹里面创建templates文件夹,存放我们的HTML模板,
还有自定义的组件/模块,
还有views文件夹,里面是视图函数

1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1"> 7 <title>用户登录</title> 8 </head> 9 <body> 10 <form method="post"> 11 {{form.user}} {{form.user.errors[0]}} 12 {{form.pwd}} {{form.pwd.errors[0]}} 13 <input type="submit" value="提交">{{msg}} 14 </form> 15 </body> 16 </html>

1 import pymysql 2 from settings import BaseConfig 3 4 5 class SQBase(): 6 @staticmethod 7 def open(cursor): 8 POOL = BaseConfig.SQL_POOL 9 conn = POOL.connection() 10 cursor = conn.cursor(cursor=cursor) # 这里等号右边的cursor是我们的形参,传入的值 11 return conn, cursor 12 13 @staticmethod 14 def close(conn, cursor): 15 conn.commit() 16 cursor.close() 17 conn.close() 18 19 @classmethod 20 def fetch_one(cls, sql, args, cursor=pymysql.cursors.DictCursor): 21 conn, cursor = cls.open(cursor) 22 cursor.execute(sql, args) 23 obj = cursor.fetchone() 24 cls.close(conn, cursor) 25 return obj 26 27 @classmethod 28 def fetch_all(cls, sql, args, cursor=pymysql.cursors.DictCursor): 29 conn, cursor = cls.open(cursor) 30 cursor.execute(sql, args) 31 obj = cursor.fetchall() 32 cls.close(conn, cursor) 33 return obj

1 from flask import request, redirect, render_template, Blueprint, session 2 from wtforms import Form 3 from ..utils.demo import SQBase 4 from wtforms import simple, validators, widgets 5 6 acc = Blueprint('account', __name__) 7 8 9 class LoginForm(Form): 10 user = simple.StringField( 11 validators=[ 12 validators.DataRequired(message='用户名不能够为空'), 13 ], 14 widget=widgets.TextInput(), 15 render_kw={'class': 'form-control', 'placeholder': 'user'} # 这是给我们的前端标签添加属性 16 ) 17 pwd = simple.PasswordField( 18 validators=[ 19 validators.DataRequired(message='密码不能为空'), 20 ], 21 widget=widgets.PasswordInput(), 22 render_kw={'class': 'form-control', 'placeholder': 'pwd'} 23 ) 24 25 26 @acc.route('/login', methods=['GET', 'POST']) 27 def login(): 28 if request.method == 'GET': 29 form = LoginForm() 30 return render_template('login.html', form=form) 31 32 form = LoginForm(formdata=request.form) 33 if not form.validate(): 34 return render_template('login.html', form=form) 35 36 fh = SQBase.fetch_one("select id,name from userinfo where name=%(user)s and pwd=%(pwd)s", form.data) 37 if fh: 38 session.permanent = True 39 session['user_info'] = {'id': fh['id'], 'name': fh['name']} 40 return redirect('/index') 41 else: 42 return render_template('login.html', msg='user or pwd is wrong', form=form)

1 from flask import Blueprint,session 2 hom=Blueprint('index',__name__) 3 @hom.route('/index') 4 def index(): 5 user_obj=session.get('user_info') 6 print('old message',user_obj) 7 session['user_info']['h1']=798 8 user_obj=session.get('user_info') 9 print('new message',user_obj) 10 return 'index'

1 from flask import Flask 2 from flask_session import Session 3 from .views import account 4 from .views import index 5 6 def create_aps(): 7 app=Flask(__name__) 8 app.config.from_object('settings.DevelopmentConfig') 9 10 app.register_blueprint(account.acc) 11 app.register_blueprint(index.hom) 12 # 将session替换成redis session 13 Session(app) 14 return app

1 from threading_pool import create_aps 2 app=create_aps() 3 if __name__=='__main__': 4 app.__call__ 5 app.run()

1 from datetime import timedelta 2 from redis import Redis 3 import pymysql 4 from DBUtils.PooledDB import PooledDB, SharedDBConnection 5 6 7 class BaseConfig(): 8 DEBUG = True 9 SECRET_KEY = 'aslgjkas' 10 PERMANENT_SESSION_LIFETIME = timedelta(minutes=20) 11 SESSION_TYPE = 'redis' 12 SQL_POOL = PooledDB( 13 creator=pymysql, # 使用链接数据库的模块 14 maxconnections=6, # 连接池允许的最大连接数,0还有None表示不限制连接数 15 mincached=2, # 初始化时,连接池中至少创建的空闲的链接,0表示不创建, 16 maxcached=4, # 连接池中最多闲置的链接,0和None表示不限制, 17 maxshared=3, # 连接池中最多共享的连接数量,0和None表示共享所有,PS:基本不用这个参数, 18 # 因为pymysql和MySQLdb等模块的threadsafety都是1,所以无论设置这个值为多少,maxcached永远为0,也就是所有链接共享 19 blocking=True, # 连接池中如果没有可用的链接,是否阻塞等待, 20 maxusage=None, # 一个连接最多被重复使用的次数,None表示无限次 21 setsession=[], # 开始会话前执行的命令列表,如['set datestyle to,''', 'set time zone...'] 22 ping=0, # pingMySQL服务端,检查是否服务可用, # 如:0=None=never, 23 # 1=default=whenever it is requested, 24 # 2=when a cursor is created, 25 # 4=when a query is executed, 26 # 7=always 27 host='127.0.0.1', 28 port=3306, 29 user='root', 30 password='123', 31 database='book_list', 32 charset='utf8' 33 ) 34 35 36 class ProductionConfig(BaseConfig): 37 SESSION_REDIS = Redis(host='192.168.13.184', port='6379') 38 39 40 class DevelopmentConfig(BaseConfig): 41 SESSION_REDIS = Redis(host='127.0.0.1', port='6379') 42 43 44 class TestingConfig(BaseConfig): 45 ...