分享

【Python之路】特别篇

 highoo 2019-03-20
登陆与注册

注册功能:

流程: 填写用户名,邮箱,获取邮箱验证码,填入密码 单击<下一步>按钮,完成注册!

1.获取邮箱验证码(具体步骤分析):

1.利用ajax 往后台传入邮箱,

2.后台表单验证,邮箱填写是否正确,     

  => 成功,则继续3,

  => 错误,写入错误信息,页面输出错误提示!

3.查询sendcode 数据库表,查询该邮箱是否是第一次发送验证码

  => 第一次发送: 数据表中插入记录 (邮箱,发送次数1,邮箱验证码,状态1,有效时间:当前时间-1小时)

  => 否则: 从数据表中查询出该邮箱验证码发送次数,

      => 如果 >5 则,再判断上次发送时间+1小时 是否大于当前时间!

          => 大于当前时间,则发送验证码,修改数据表记录 (发送次数+1,邮箱验证码,有效时间)

                            => 小于当前时间,则为多次恶意发送,不操作,写入错误信息,需要等待1小时,

                 => 如果<5 则直接发送验证码,修改数据表记录 (发送次数+1,邮箱验证码,有效时间)

4.json信息返回。

SendEmailCodeHandler
commons.py 公共方法:生成4位验证码
前端JQ:发送验证码

2.验证码发送过程: 页面倒计时

原理:设计计时器,每1秒修改1次text值, 时间小于0时,取消计时器

前端JQ:倒计时

3.账号注册 

1.JQ获取前台输入表单内容

2.ajax传输给后台,建立表单验证

  => 正确,继续3

  => 错误,返回错误信息,页面显示错误信息

3.数据库中查询用户邮箱是否存在

  => 不存在,插入数据库,继续4

  => 存在,返回错误信息,页面显示

4.注册账号完成,写入session,注册完成页面刷新实现自动登录

前端JQ:获取输入值
RegisterUserHandler

表单错误时,页面信息提示(效果图):

登录功能:

原理:与注册功能类似

1.图片验证码:点击验证码,自动更改

验证码为后台生成的图片,每点击一次,src地址后面 多加?实现切换

<div class="inp-block">
    <input type="text" name="phoneregister" placeholder="请输入验证码" id="u-code" class="phonenum"  autocomplete="off"/>
    <img src="/check_code" onclick='ChangeCode();' id='imgCode' class="codeimg">
</div>
前端JQ:点击改变验证码
前端JQ:登录按钮
CheckcodeHandler
LoginUserHandler
check_code.py
表单验证

设计思想: 无论表单通过form形式,或者ajax形式,发送数据给后端,我们都要先通过:某些规则进行过滤和验证,再对其进行数据的插入,修改等操作

实现思路:1,有form表单数据来临时,初始化一个表单类,传入self;

     2,自动获取form上数据字段,self.get_arguments(name),name与前端input标签的name名字一一对应;

     3,通过表单类,调用检测方法 check_value(),

     4,如果form表单数据,符合自定义的规则,以字典形式返回数据,{ ‘前端input的name值’:‘input的value值’ } =》 存储在表单类的 self._value_dict 中

     5,如果form表单数据,不符合自定义的规则,以字典形式返回错误信息,{ ‘前端input的name值’:‘错误信息’ } =》 存储在表单类的 self._error_dict 中

 

1. 定义一个表单类 LoginForm ,__init__方法中对象名为 前端input标签的name值

   required 是否可以为空值, error_dict 定义错误信息输出内容

复制代码
class LoginForm(BaseForm):
    def __init__(self):
        self.username = UsernameField(required=True,error_dict={'required':'用户名不能为空' , 'valid':'用户名错误'})
        self.password = PasswordField(required=True,error_dict={'required':'密码不能为空' , 'valid':'用户名或密码错误'})
        self.code = CodeField(required=True,error_dict={'required':'验证码不能为空' , 'valid':'验证码错误'})
        self.remember = CheckBoxField(required=False,error_dict={'valid':'格式错误'})
        super(LoginForm, self).__init__()
复制代码

2. 继承BaseForm类,该类初始化了,当前Form表单共用的最后返回数据和错误信息的字典对象

复制代码
class BaseForm():
    def __init__(self):
        self._value_dict = {}
        self._error_dict = {}
        self._valid_status = True
    
    def check_value(self):
        ....
复制代码

  check_value() 执行获取前端输入的数据,self.get_argument(xxxx) 并且根据每个input标签定义的规则去验证数据的正确性 (上文的UsernameField,PasswordField..等)

  通过self.__dict__循环获取LoginForm的成员对象,调用Field的validate()方法,验证Form表单中每一个的值。验证正确,信息存储在self._value_dict 中, 错误信息存储在self._error_dict 中

复制代码
def check_value(self,handler):
    for key,regular in self.__dict__.items():
        input_value = handler.get_argument(key,None)
        regular.validate(key,input_value)
    if regular.is_valid:
        self._value_dict[key] = regular.value
    else:
        self._error_dict[key] = regular.error
复制代码
BaseForm 完整代码

3. Field 自定义的规则类

  为前端input标签,定义不同的验证规则(正则表达式),验证用户输入的数据

复制代码
class PasswordField(Field):
    REGULAR = "[0-9 | A-Z | a-z]{6,16}"
    def __init__(self,required=True,error_dict=None):

        self.error_dict = {}   #错误信息
        if error_dict:
            self.error_dict.update(error_dict)   #用户自定义的错误信息

        self.required = required
        super(PasswordField, self).__init__()
复制代码

   继承父类Field,初始化存储信息的成员

复制代码
class Field:

    def __init__(self):
        self.is_valid = False   # 验证规则是否通过,默认False
        self.name = None
        self.value = None      # 获取的前端input值
        self.error = None

    def validate(self, name, input_value):
        ...
复制代码

    执行validate()方法,

  1.先判断该值是否允许为空?,

    => 可以为空,验证通过,self.value = input输入值

    => 不可以为空, 判断 input输入值 是否为空?

        => input输入值为空,self.error = 定义的错误信息(required)

        => 不为空,继续正则表达式判断,re.match(REGULAR,input_value)

            => 正则通过,self.value = input输入值, self.is_valid = True

            => 正则不通过, self.error = 定义的错误信息(valid)

Field 完整代码

自定义的Field 供参考:

CheckBoxField
FileField
EmailField (input类型为text通用)
Session   

设计思想: 利用Cookie 自定义一个Session来存储每个用户信息

实现思路: 1. Session信息设计成一个大字典,key对应用户唯一识别加密串,value对应空字典{}存储用户信息,存放在服务端上。

      2. 为用户请求生成一个唯一加密串,写入到Cookie信息中,Session_id = 加密串,用于区分每一个用户。

      3. 当用户请求到来时,获取该请求的Cookie信息,判断是否存在Session_id(用户唯一识别加密串)?

      => 如果存在Session_id 并且在 Session大字典中找到相同的 key,记录Session_id

      => 其他情况下一律,生成加密串,写入到Cookie中,同时写入到 Session大字典中

复制代码
class CacheSession():
    session_id = "__balabala__"     # Cookie中为Session存储的名字
    session_container = {}        # Session大字典

    def __init__(self,handler):
        self.handler = handler
        client_random_str = self.handler.get_cookie(CacheSession.session_id,None)
        if client_random_str and client_random_str in CacheSession.session_container:
            self.random_str = client_random_str
        else:
            self.random_str = self.__container__random__str()
            CacheSession.session_container[self.random_str] = {}

        expires_time = time.time() + config.SESSION_EXPIRES
        self.handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time)  # 方便后续定义过期时间!

    def __container__random__str(self):      # 生成加密串
        hash = hashlib.md5()
        hash.update(bytes(str(time.time()), encoding='utf-8'))
        random_str = hash.hexdigest()
        return random_str
复制代码

利用方法:1. 当用户请求到达每个Handler时,我们都需要先实例化一个CacheSession(),

     2. 此时我们可以定义一个父类BaseHandler,initialize() 方法中写入要执行代码,

复制代码
import tornado.web
form session import SessionFactory

class BaseHandler(tornado.web.RequestHandler):
    def initialize(self):
        self.session = SessionFactory.get_session_obj(self)
复制代码

可以看到,我们在session.py中定义了一个新的类SessionFactory,用来选择合适的方法,初始化Session,

该类通过读取配置文件config中的SESSION_TYPE选择适合的Session类进行初始化,并且返回一个Session对象,该对象最终存储在 self.session中。

复制代码
class SessionFactory():

    @staticmethod
    def get_session_obj(handler):
        if config.SESSION_TYPE == 'cache':
            obj = CacheSession(handler)
        elif config.SESSION_TYPE == 'memcached':
            obj = MemcachedSession(handler)
        elif config.SESSION_TYPE == 'redis':
            obj = RedisSession(handler)
        return obj
复制代码

Handler 中使用Session

class LoginUserHandler(BaseHandler):
    def post(self, *args, **kwargs):
        self.session['is_login'] = 1
        self.write('ok')

1.缓存Session

View Code

2.memcache session

View Code

3.radis session

View Code

需要注意的是:__setitem__,__getitem__和__delitem__  使用类似字典方式设置,访问,删除成员。

在缓存Session 中,他们的使用方法与字典差别不大。

在memcache 中,键值对key,value 都是以字符串的形式存储的,

     在设置值前需要将value值通过json转换成字典形式,再对字典进行操作,操作完毕后,用json转换回字符串,存储回原来位置!

在redis 中,选用hash操作进行存储,如果待存储的value值为字典,需要先把value通过json转换成字符串,再存储在redis中,

     获取某个key的value值时,由于hash中value是以bytes存储,需要先转换成str类型,再判断该key存储的是字典,还是普通字符串

Session所有的完整代码:

session.py
request_handle.py
config.py 配置文件
分页

设计思路:与Tornado篇分页同理

前端:

前端页面

后台Url配置:

1
(r"/index/(?P<page>\d*)", IndexHandler),

后台Handle:

复制代码
class IndexHandler(BaseHandler):
    def get(self, page):
        query = QueryContent()
        page_obj = pager.Pagiantion(page, all_item=query.queryCounts(), per_num=5)  #page 当前页码 , all_item 总数据条数, per_num 每页显示条数
        str_page = page_obj.page_str('/index/')

        self.render("index.html", str_page=str_page )
复制代码

Pagiantion 分页类:

Pagiantion 分页类
分页标签 Css

页面登陆验证(装饰器方式实现)

1.普通登陆验证

1
2
3
4
5
6
7
8
9
10
LOGIN_URL = '/login'
def auth_login_redirect(func):
  
    def inner(self, *args, **kwargs):
        if not self.session['is_login']:
            self.redirect(config.LOGIN_URL)
            return
        func(self, *args, **kwargs)
    return inner

2.ajax提交数据的登陆验证

1
2
3
4
5
6
7
8
9
10
def auth_login_json(func):
  
    def inner(self, *args, **kwargs):
        if not self.session['is_login']:
            rep = BaseResponse()
            rep.summary = "auth failed"
            self.write(json.dumps(rep.__dict__))
            return
        func(self, *args, **kwargs)
    return inner
文件上传

为了美观 , 文件上传标签一半由两部分组成 file标签和 button标签

1
2
3
4
<div id="main" class="up-block">
    <input name="file" id="my_file" class="file-path" type="file" onchange="imagechange()"/>
    <input type="button" name="action" value="Upload" class="a-upload"/>
<div>

file标签会设置 透明度 和 定位在button上 , 绑定onchange事件

复制代码
.up-block{
    position: relative;
}
.file-path{
    position: absolute;
    width: ..px;
    height: ..px;
    font-size: ..px;
    opacity: 0;
        z-index: 10;
}
复制代码

图片上传后,展示在上传页面:

方法一:利用iframe实现

View Code

抽屉网实现,完整代码:

jQ 代码
Html 代码
Css 代码

方法二:ajax实现

通过Ajax的FormData对象来实现。详情参考ajax篇

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<input type="file" name="uploadimage" id="uploadimage">
var fileObj = $("#uploadimage")[0].files[0];
var form = new FormData();
form.append("uploadimage", fileObj);
$.ajax({
    url:'/uploadimg',
    type:'POST',
    data:form,
    processData: false,  // tell jQuery not to process the data
    contentType: false,
    success:function (data, statusText, xmlHttpRequest) {
        obj = JSON.parse(data);
    }
})

  

  

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多