Python Web 框架工具包 werkzeug

一、什么是werkzeug 

werkzeug 官方的介绍说是一个 WSGI 工具包,不是一个web服务器,也不是一个web框架,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等;例如我最常用的 Flask 框架就是一 Werkzeug 为基础开发的。

Werkzeug 教程基础中文文档

二、Werkzeug实现密码校验功能

使用Werkzeug实现密码散列,最关键的是使用其中security模块的generater_password_hash()和check_password_hash()。

from werkzeug.security import generate_password_hash,check_password_hash

class User(db.Model):
 __tablename__ = 'users'
 id = db.Column(db.Integer, primary_key=True)#id列
 username = db.Column(db.String(64), unique=True, index=True)  #username列
 role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) #role_id列
 password_hash = db.Column(db.String(128)) #密码hash列
 
 @property
 def password(self): #访问password属性
  raise AttributeError('password is not a readable attribute')
 
 # 对保存到数据库中的密码进行加盐 
 # 什么是盐?
 # 通过一个随机字符串或指定字符串与原有字符串进行混淆处理,等到一个新的字符串,这个过程称为加盐处理。
 @password.setter
 def password(self,password): #设置password属性
  self.password_hash = generate_password_hash(password)  #默认加盐了
 
 # 输入密码时进行校验
 def verify_password(self,password):#验证密码
  return check_password_hash(self.password_hash,password)
 
 def __repr__(self):
  return '<user r="">' % self.username</user>

1、generate_password_hash(password, method=pbkdf2:sha1, slat_length=8)

method指定哈希变化的算法,默认sha1,salt_length指定‘盐的长度’,默认是8位。password是必须指定的。

返回计算得出的128位哈希值

2、check_password_hash(hash,password)

hash是密码散列值(一般存于数据库),password是输入需比较的密码。

返回的是True或者False

三、local 模块

1、简介

local模块中,Werkzeug实现了类似Python标准库中threading.local的功能。threading.local是线程局部变量,也就是每个线程的私有变量,具有线程隔离性,可以通过线程安全的方式获取或者改变线程中的变量。参照threading.local,Werkzeug实现了比thread.local更多的功能。

总结起来: 以上文档解释了对于“并发”问题,多线程并不是唯一的方式,在Python中还有“协程”。“协程”的一个显著特点在于是一个线程执行,一个线程可以存在多个协程。也可以理解为:协程会复用线程。对于WSGI应用来说,如果每一个线程处理一个请求,那么thread.local完全可以处理,但是如果每一个协程处理一个请求,那么一个线程中就存在多个请求,用thread.local变量处理起来会造成多个请求间数据的相互干扰。

对于上面问题,Werkzeug库解决的办法是local模块。local模块实现了四个类:

  • Local
  • LocalStack
  • LocalProxy
  • LocalManager

本文重点介绍前两个类的实现。

2、Local类

Local类能够用来存储线程的私有变量。在功能上这个threading.local类似。与之不同的是,Local类支持Python的协程。在Werkzeug库的local模块中,Local类实现了一种数据结构,用来保存线程的私有变量,对于其具体形式,可以参考它的构造函数:

class Local(object):
    __slots__ = ('__storage__', '__ident_func__')
    def __init__(self):
        object.__setattr__(self, '__storage__', {})
        object.__setattr__(self, '__ident_func__', get_ident)

从上面类定义可以看出,Local类具有两个属性:__storage____ident_func__。从构造函数来看,__storage__是一个字典,而__ident_func__是一个函数,用来识别当前线程或协程。

1. __ident_func__

关于当前线程或协程的识别,local模块引入get_ident函数。如果支持协程,则从greenlet库中导入相关函数,否则从thread库中导入相关函数。调用get_ident将返回一个整数,这个整数可以确定当前线程或者协程。

try:
    from greenlet import getcurrent as get_ident
except ImportError:
    try:
        from thread import get_ident
    except ImportError:
        from _thread import get_ident

2. __storage__

__storage__是一个字典,用来存储不同的线程/协程,以及这些线程/协程中的变量。以下是一个简单的多线程的例子,用来说明__storage__的具体结构。

import threading
from werkzeug.local import Local

l = Local()
l.__storage__
def add_arg(arg, i):
    l.__setattr__(arg, i)
for i in range(3):
    arg = 'arg' + str(i)
    t = threading.Thread(target=add_arg, args=(arg, i))
    t.start()
l.__storage__

上面的例子,具体分析为:

  • 首先,代码创建了一个Local的实例l,并且访问它的__storage__属性。由于目前还没有数据,所以l.__storage__的结果为{};
  • 代码创建了3个线程,每个线程均运行add_arg(arg, i)函数。这个函数会为每个线程创建一个变量,并对其赋值;
  • 最后,再次访问l.__storage__。这次,l实例中将包含3个线程的信息。其结果为:
{20212: {'arg0': 0}, 20404: {'arg1': 1}, 21512: {'arg2': 2}}

从以上结果可以看出,__storage__这个字典的键表示不同的线程(通过get_ident函数获得线程标识数值),而值表示对应线程中的变量。这种结构将不同的线程分离开来。当某

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值