werkzeug综合应用 - pythonweb(4)
werkzeug综合应用 - pythonweb(4)
本文将通过一个完整的用户管理的实例使werkzeug工作起来,并且使代码分层,看起来和SpringMVC的层次相同,完成用户注册、用户登录两个功能。前提说明:
-
数据模式:User(id, uname, telephone, password)
-
文件结构:
controller | |_____ __init__.py # 导入文件,使得装饰器可以被扫描 | |_____ user_controller.py dao | |_____ __init__.py | |_____ user_dao.py utils | |_____ session.py | |_____ util.py config.py # 配置文件,配置模板、数据库连接,声明全局变量 | application.py # 处理请求相应、核心应用类 | __init__.py -
python生成验证码
4.1 控制层
如何在方法上直接通过注解绑定请求路径呢?python的解决方案是使用装饰器
from werkzeug.routing import Map
from werkzeug.routing import Rule# 全局配置: 路径映射 config.pyurl_map = Map()# 使得与路径匹配的是可直接调用的函数 util.py
def route(rule, method="GET", **kwargs):def decorate(func):kwargs['endpoint'] = funcurl_map.add(Rule(rule, methods=[method], **kwargs))return funcreturn decorate# 同一种类型的请求组织在UserController一个类中 user_controller.py
class UserController:@route("/user/register")def to_add(self, request):return render_template("front/user/register.html", sessionScope=request.session)# 请求处理,函数调用 application.py
# 第一个类相关的位置参数传入None即可
adapter = url_map.bind_to_environ(environ)
endpoint, args = adapter.match()
response = endpoint(None, request, **args)
4.2 数据层:
得益于python字典以及字符串的格式化,很容易就会格式化拼接得到一条SQL语句,我们执行拿到结果即可。为了避免频繁写连接数据库准备和关闭数据库代码,直接统一到一个方法进行注解:
# 配置数据库连接池 config.py
pool = PooledDB(**{**conn_config, **db_config}
)# 装饰到方法上 util.py
def context_cr(use=''):def wrapper(func):@wraps(func)def inner(*args, **kwargs):conn = pool.connection()cr = conn.cursor(DictCursor)args[0].cr = crtry:res = func(*args, **kwargs)except Exception as e:raise eelse:return resfinally:cr.close()conn.close()return innerreturn wrapper# context_cr 修饰类的方法时, args[0]封装的是类的实例,所以把游标放到类的实例中去,方便方法使用
# user_dao.py
class UserDao:@context_crdef insert(self, obj, **kwargs):sql = """INSERT INTO user(uname, password, telephone) VALUES('{uname}', '{password}', '{telephone}')""".format(**obj)try:self.cr.execute(sql)self.cr._con.commit()return Trueexcept Exception as e:return False
# 全局使用
user_dao = UserDao()
4.3 用户登录状态的记录:
SpringMVC中,我们可以直接使用HttpSession来存放用户登录的登录信息,werkzeug在0.9版本前还提供了session的解决方案,但在后续的模块中已经取消了werkzeug.contrib模块相关内容,因为session机制极具灵活,为了确保分布式应用中可以共享session, 可以将session放到redis集群里 分布式session方案。0.9版本以前提供了FileSystemSessionStore来将session信息存放到本地文件系统,以及提供了一个SessionMiddleWare解决如何将session与浏览器cookie绑定,我们可以下载0.9版本的代码学习session的实现方法,实现一个redis或sqlite的session方案,本文采用本地文件系统存放session。
# session配置,session堆 config.py
session_store = FilesystemSessionStore(path=session_path)# 请求处理session及响应装配cookie
class Root:def __init__(self):self.dispatch_request = SharedDataMiddleware(self.dispatch_request, {"/static": static_path,"/img": image_path,})def dispatch_request(self, environ, start_response):request = Request(environ)sid = request.cookies.get("sid", None)if not sid:session = session_store.new()else:session = session_store.get(sid)request.session = session# ...... 路由匹配代码,省略def wrapped_start_response(status, headers, exc_info=None):headers.append(('Set-Cookie', dump_cookie('sid', session.sid)))return start_response(status, headers, exc_info)start_response_ = sid and start_response or wrapped_start_responsereturn response(environ, start_response_)def __call__(self, environ, start_response):return self.dispatch_request(environ, start_response)
4.4 python 生成验证码:
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import os
from io import BytesIO_letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(10))) # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))def generate_validate_code(size=(120, 30),chars=init_chars,img_type="JPEG",mode="RGB",bg_color=(230, 230, 230),fg_color=(18, 18, 18),font_size=20,length=4,draw_lines=True,n_line=(1, 2),draw_points=True,point_chance=1):'''@param size: 图片的大小,格式(宽,高),默认为(120, 30)@param chars: 允许的字符集合,格式字符串@param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG@param mode: 图片模式,默认为RGB@param bg_color: 背景颜色,默认为白色@param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF@param font_size: 验证码字体大小@param length: 验证码字符个数@param draw_lines: 是否划干扰线@param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效@param draw_points: 是否画干扰点@param point_chance: 干扰点出现的概率,大小范围[0, 100]@return: [0]: 二进制图像数据流@return: [1]: 验证码'''width, height = size # 宽, 高img = Image.new(mode, size, bg_color) # 创建图形draw = ImageDraw.Draw(img) # 创建画笔def get_chars():'''生成给定长度的字符串,返回列表格式'''return random.sample(chars, length)def create_lines():'''绘制干扰线'''line_num = random.randint(*n_line) # 干扰线条数for i in range(line_num):# 起始点begin = (random.randint(0, width), random.randint(0, height))# 结束点end = (random.randint(0, width), random.randint(0, height))draw.line([begin, end], fill=(0, 0, 0))def create_points():'''绘制干扰点'''chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]for w in range(width):for h in range(height):tmp = random.randint(0, 100)if tmp > 100 - chance:draw.point((w, h), fill=(0, 0, 0))def draw_code():'''绘制验证码字符'''c_chars = get_chars()d_chars = ' '.join(c_chars) # 每个字符前后以空格隔开font_type = os.path.join(os.path.dirname(__file__), 'DejaVu-Sans-Bold.ttf')font = ImageFont.truetype(font_type, font_size)font_width, font_height = font.getsize(d_chars)draw.text(((width - font_width) / 3, (height - font_height) / 3), d_chars, font=font, fill=fg_color)return ''.join(c_chars).lower()if draw_lines:create_lines()if draw_points:create_points()code = draw_code()# 图形扭曲参数params = [1 - float(random.randint(1, 2)) / 100,0,0,0,1 - float(random.randint(1, 10)) / 100,float(random.randint(1, 2)) / 500,0.001,float(random.randint(1, 2)) / 500]img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)f = BytesIO() # 用完之后,BytesIO会自动清掉# img.save(f, 'png')data = f.getvalue()return data, code
werkzeug是可以直接构建web应用的,需要我们自己做的事情比较多,但是可以更好的理解一个web应用的运行方式:路由的匹配、请求的处理、响应的构造,所以学习werkzueg来入门pythonweb是非常有必要的,后续我们可以学习其他python重型web框架,有了基础学习起来更加得心应手,至此,werkzeug篇完。后续会将这个例子上传到github供大家下载。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
