• 【Python之路】特别篇--抽屉新热榜


    登陆与注册

    注册功能:

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

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

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

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

      => 成功,则继续3,

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

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

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

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

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

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

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

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

    4.json信息返回。

    import json
    import datetime
    
    from core.request_handle import BaseHandler
    # 公共方法
    from backend import commons,message
    # 数据库查询
    from models.sendcode import Insert,QueryCounts,Update
    from models.userinfo import InsertUser
    # 表单验证
    from forms.account import emailForm,registerForm
    
    
    class SendEmailCodeHandler(BaseHandler):
        def post(self):
            obj = emailForm()
            val, success_info, error_info = obj.check_value(self)
            if not error_info:
                email = [success_info['email']]
                now = datetime.datetime.now()
                que = QueryCounts()
                ret = que.checkstime(email)
                if ret:
                    if ret['stime'] < 5:
                        UpdateCode(email)
                    else:
                        if (ret['ctime'] + datetime.timedelta(hours=1)) > now :
                            error_info['stime'] = '验证码发送次数过多,请1小时后再发送'
                        else:
                            UpdateCode(email)
                else:
                    InsertCode(email)
            data = {'success_info': success_info, 'error_info': error_info}
            self.write(json.dumps(data))
    
    
    # 第一次发送code 数据表添加
    def InsertCode(email):
        code = commons.random_code()   # 生成4位随机验证码(字母+数字)
        message.send_email(email, code)
        ins = Insert()
        ins.insertcode(email, code)
        print(email, code)
    
    # 多次发送, 数据表修改
    def UpdateCode(email):
        code = commons.random_code()
        message.send_email(email, code)
        update = Update()
        update.updatestime(email, code)
        print(email, code)
    SendEmailCodeHandler
    import random
    import string
    
    def random_code():
        code = ''.join(random.sample(string.ascii_letters + string.digits, 4))
        return code
    commons.py 公共方法:生成4位验证码
    //注册:生成邮箱验证码:
    $('#email-code').on('click',function () {
        var email = $('#re-email').val();
        $.ajax({
            url:'/email-code',
            type: 'POST',
            dataType: 'json',
            data:{'email':email},
            success: function(obj){
                if( isEmptyObject(obj['error_info']) ){
                    $('.register-error').text('');
                    $('.ac-code').addClass('hide');
                    $('.ac-time').removeClass('hide');
                    timechange();
                }
                $.each(obj['error_info'],function (k,v) {
                    $('.register-error').text(v);
                    return false;
                });
            }
        })
    });
    前端JQ:发送验证码

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

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

    //邮箱验证码倒计时:
    function timechange() {
        var time = 60;
        var interval = setInterval(function () {
            if(time <= 0 ){
                $('.ac-time').addClass('hide');
                $('.ac-code').removeClass('hide');
                clearInterval(interval);
            }
            time = time - 1;
            var temp = "已发送("+time+"s)";
            $('.ac-time').text(temp)
        },1000)
    }
    前端JQ:倒计时

    3.帐号注册 

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

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

      => 正确,继续3

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

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

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

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

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

    //注册帐号
    $('#register-next').on('click',function () {
        registerUser();
        clearinput();
    });
    function registerUser(){
        var username= $('#re-username').val();
        var email = $('#re-email').val();
        var code = $('#re-code').val();
        var password = $('#re-password').val();
        $.ajax({
            url:'/register',
            type: 'POST',
            dataType: 'json',
            data:{'username':username,'email':email,'code':code,'password':password},
            success: function(obj){
                if( isEmptyObject(obj['error_info']) ){
                    $('.register-error').text('');
                    //跳转(隐藏输入页面):
                    $('.login-block').addClass('hide');
                    $('.register-info').removeClass('hide');
                }
                $.each(obj['error_info'],function (k,v) {
                    $('.register-error').text(v);
                    return false;
                });
            }
        })
    }
    前端JQ:获取输入值
    class RegisterUserHandler(BaseHandler):
        def post(self):
            obj = registerForm()
            val, success_info, error_info = obj.check_value(self)
            print(val, success_info, error_info)
            if not error_info:
                ins = InsertUser()
                ins.inser(success_info['username'],success_info['password'],success_info['email'])
                self.session['is_login'] = 1
                self.session['username'] = success_info['username']
            data = {'success_info': success_info, 'error_info': error_info}
            self.write(json.dumps(data))
    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>
    //注册页面验证码切换
    function ChangeCode() {
        var code = document.getElementById('imgCode');
        code.src += '?';
    }
    前端JQ:点击改变验证码
    //登录,确定按钮:(邮箱形式)
    $('.login-btn').on('click',function () {
        var username = $('#username').val();
        var password = $('#password').val();
        var code = $('#u-code').val();
        var remember = 0;
        if($('#phone-remember').is(':checked')){
            remember = 1;
        }
        $.ajax({
            url:'/userlogin',
            type: 'POST',
            dataType: 'text',
            data:{'username':username,'password':password,'code':code,'remember':remember},
            success: function(data, statusText, xmlHttpRequest){
                obj = JSON.parse(data);
                if( isEmptyObject(obj['error_info']) ){
                    $('.login-error').text('');
                    window.location.reload();
                }
                $.each(obj['error_info'],function (k,v) {
                    $('.login-error').text(v);
                    return false;
                });
            }
        })
    });
    前端JQ:登录按钮
    import io
    
    from backend.utils import check_code
    from core.request_handle import BaseHandler
    
    class CheckcodeHandler(BaseHandler):
        def get(self, *args, **kwargs):
            mstream = io.BytesIO()
            img, code = check_code.create_validate_code()
            self.session['code'] = code
            print(self.session['code'])
            img.save(mstream, "GIF")
            self.write(mstream.getvalue())
    CheckcodeHandler
    import tornado.ioloop
    import tornado.web
    import json
    import os
    import sys
    
    from core.request_handle import BaseHandler
    from models.userinfo import QueryUser
    from forms.account import LoginForm
    
    class LoginUserHandler(BaseHandler):
        def post(self, *args, **kwargs):
            obj = LoginForm()
            val, success_info, error_info = obj.check_value(self)
            print(val, success_info, error_info)
            if not error_info:
                if self.session['code'].upper() == success_info['code'].upper():
                    query  = QueryUser()
                    ret = query.checkusername(success_info['username'],success_info['password'])
                    if ret:
                        self.session['is_login'] = 1
                        self.session['username'] = ret['username']
                        self.session['user_id'] = ret['user_id']
                    else:
                        error_info = { 'username' : '用户名或密码错误'}
                else:
                    error_info = {'code': '验证码错误'}
            data = { 'success_info': success_info , 'error_info': error_info }
            self.write(json.dumps(data))
    LoginUserHandler
    #!/usr/bin/env python
    #coding:utf-8
    
    import random
    from PIL import Image, ImageDraw, ImageFont, ImageFilter
    
    _letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小写字母,去除可能干扰的i,l,o,z
    _upper_cases = _letter_cases.upper()  # 大写字母
    _numbers = ''.join(map(str, range(3, 10)))  # 数字
    init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
    
    def create_validate_code(size=(120, 30),
                             chars=init_chars,
                             img_type="GIF",
                             mode="RGB",
                             bg_color=(255, 255, 255),
                             fg_color=(0, 0, 255),
                             font_size=18,
                             font_type="Monaco.ttf",
                             length=4,
                             draw_lines=True,
                             n_line=(1, 2),
                             draw_points=True,
                             point_chance = 2):
        '''
        @todo: 生成验证码图片
        @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 font_type: 验证码字体,默认为 ae_AlArabiya.ttf
        @param length: 验证码字符个数
        @param draw_lines: 是否划干扰线
        @param n_lines: 干扰线的条数范围,格式元组,默认为(1, 2),只有draw_lines为True时有效
        @param draw_points: 是否画干扰点
        @param point_chance: 干扰点出现的概率,大小范围[0, 100]
        @return: [0]: PIL Image实例
        @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, size[0]), random.randint(0, size[1]))
                #结束点
                end = (random.randint(0, size[0]), random.randint(0, size[1]))
                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 create_strs():
            '''绘制验证码字符'''
            c_chars = get_chars()
            strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开
    
            font = ImageFont.truetype(font_type, font_size)
            font_width, font_height = font.getsize(strs)
    
            draw.text(((width - font_width) / 3, (height - font_height) / 3),
                        strs, font=font, fill=fg_color)
    
            return ''.join(c_chars)
    
        if draw_lines:
            create_lines()
        if draw_points:
            create_points()
        strs = create_strs()
    
        # 图形扭曲参数
        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) # 滤镜,边界加强(阈值更大)
    
        return img, strs
    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
    class BaseForm():
        def __init__(self):
            self._value_dict = {}
            self._error_dict = {}
            self._valid_status = True
    
    
        def check_value(self,handler):
            for key,regular in self.__dict__.items():
                if key.startswith('_'):
                    continue
                if type(regular) == fields.CheckBoxField:
                    input_value = handler.get_arguments(key)  # checkbox取值
                elif type(regular) == fields.FileField:
                    file_list = handler.request.files.get(key,[])  # 文件对象
                    input_value = []
                    for item in file_list:
                        input_value.append(item['filename'])
                else:
                    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
                    self._valid_status = False
            return self._valid_status
    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)

    class Field:
    
        def __init__(self):
            self.is_valid = False
            self.name = None
            self.value = None
            self.error = None
    
        def validate(self, name, input_value):
            self.name = name
    
            if not self.required:  # 可以为空
                self.value = input_value
                self.is_valid = True
            else:
                if not input_value:
                    if self.error_dict.get('required', None):
                        self.error = self.error_dict['required']
                    else:
                        self.error = '%s is requires ' % (name)
                else:
                    val = re.match(self.REGULAR, input_value)
                    if not val:
                        if self.error_dict.get('valid', None):
                            self.error = self.error_dict['valid']
                        else:
                            self.error = '%s is valid ' % (name)
                    else:
                        self.value = input_value
                        self.is_valid = True
    Field 完整代码

    自定义的Field 供参考:

    class CheckBoxField(Field):
        REGULAR = "^d+$"
    
        def __init__(self,required=True,error_dict=None):
    
            self.error_dict = {}
            if error_dict:
                self.error_dict.update(error_dict)
            self.required = required
            super(CheckBoxField, self).__init__()
    
        def validate(self,name,input_value):
            if not self.required:
                self.value = input_value
                self.is_valid = True
            else:
                if not input_value:
                    if self.error_dict.get('required',None):
                        self.error = self.error_dict['required']
                    else:
                        self.error = '%s is requires '%(name)
                else:
                    if isinstance(name, list):
                        self.is_valid = True
                        self.value = input_value
                    else:
                        if self.error_dict.get('valid', None):
                            self.error = self.error_dict['valid']
                        else:
                            self.error = "%s is invalid" % name
    CheckBoxField
    class FileField(Field):
        REGULAR = "^(w+.jpg)|(w+.jpeg)|(w+.gif)|(w+.png)$"
    
        def __init__(self, required=True, error_dict=None):
            self.error_dict = {}
            if error_dict:
                self.error_dict.update(error_dict)
            self.required = required
            self.value = []
            self.success_file_name_list = []
            super(FileField, self).__init__()
    
        def validate(self, name, all_file_name_list):
            self.name = name
            if not self.required:
                self.value = all_file_name_list
            else:
                if not all_file_name_list:
                    self.is_valid = False
                    if self.error_dict.get('required', None):
                        self.error = self.error_dict['required']
                    else:
                        self.error = '%s is requires ' % (name)
                else:
                    for file_name in all_file_name_list:
                        if not file_name or not file_name.strip():
                            if self.error_dict.get('required', None):
                                self.error = self.error_dict['required']
                            else:
                                self.error = "%s is required" % name
                                self.is_valid = False
                            break
                        else:
                            val = re.match(FileField.REGULAR, file_name)
                            if not val:
                                self.is_valid = False
                                if self.error_dict.get('valid', None):
                                    self.error = self.error_dict['valid']
                                else:
                                    self.error = '%s is valid ' % (name)
                                break
                            else:
                                self.value.append(file_name)
    FileField
    class EmailField(Field):
    
        REGULAR = "^(w)+(.w+)*@(w)+((.w+)+)$"
    
        def __init__(self, required=True, error_dict=None):
    
            self.error_dict = {}  # 错误信息
            if error_dict:
                self.error_dict.update(error_dict)  # 用户自定错误信息
            self.required = required
            super(EmailField, self).__init__()
    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

    import time
    import hashlib
    import config
    import memcache
    import json
    import redis
    
    class CacheSession():
        session_id = "__balabala__"
        session_container = {}
    
        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
    
        def __setitem__(self,key,value):
            CacheSession.session_container[self.random_str][key] = value
    
        def __getitem__(self,key):
            result = CacheSession.session_container[self.random_str].get(key,None)
            return result
    
        def __delitem__(self,key):
            if key in CacheSession.session_container[self.random_str]:
                del CacheSession.session_container[self.random_str][key]
    View Code

    2.memcache session

    conn = memcache.Client(['127.0.0.1:11210'], debug=True)
    
    class MemcachedSession():
        session_id = "__balabala__"
    
        def __init__(self,handler):
            self.handler = handler
            client_random_str = self.handler.get_cookie(MemcachedSession.session_id,None)
            if client_random_str and conn.get(client_random_str):
                self.random_str = client_random_str
            else:
                self.random_str = self.__container__random__str()
                conn.set(self.random_str,json.dumps({}),config.SESSION_EXPIRES)
    
            conn.set(self.random_str, conn.get(self.random_str), config.SESSION_EXPIRES)
    
            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
    
        def __setitem__(self,key,value):
            ret = conn.get(self.random_str)
            ret_dict = json.loads(ret)
            ret_dict[key] = value
            conn.set(self.random_str,json.dumps(ret_dict),config.SESSION_EXPIRES)
    
        def __getitem__(self,key):
            ret = conn.get(self.random_str)
            ret_dict = json.loads(ret)
            result = ret_dict.get(key,None)
            return result
    
        def __delitem__(self, key):
            ret = conn.get(self.random_str)
            ret_dict = json.loads(ret)
            del ret_dict[key]
            conn.set(self.random_str, json.dumps(ret_dict), config.SESSION_EXPIRES)
    View Code

    3.radis session

    pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
    r = redis.Redis(connection_pool=pool)
    
    class RedisSession():
        session_id = "__balabala__"
    
        def __init__(self, handler):
            self.handler = handler
            client_random_str = self.handler.get_cookie(RedisSession.session_id, None)
            if client_random_str and r.exists(client_random_str):
                self.random_str = client_random_str
            else:
                self.random_str = self.__container__random__str()
                r.hset(self.random_str, None, None)
    
            r.expire(self.random_str,config.SESSION_EXPIRES)
    
            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
    
        def __setitem__(self, key, value):
            if type(value) == dict:
                r.hset(self.random_str, key, json.dumps(value))
            else:
                r.hset(self.random_str, key, value)
    
        def __getitem__(self, key):
            ret = r.hget(self.random_str,key)
            if ret :
                ret_str = str(ret,encoding='utf-8')
                try:
                    result = json.loads(ret_str)
                except:
                    result = ret_str
                return result
            else:
                return ret
    
        def __delitem__(self, key):
            r.hdel(self.random_str, key)
    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所有的完整代码:

    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    
    
    import time
    import hashlib
    import config
    import memcache
    import json
    import redis
    
    
    class CacheSession():
        session_id = "__balabala__"
        session_container = {}
    
        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
    
        def __setitem__(self,key,value):
            CacheSession.session_container[self.random_str][key] = value
    
        def __getitem__(self,key):
            result = CacheSession.session_container[self.random_str].get(key,None)
            return result
    
        def __delitem__(self,key):
            if key in CacheSession.session_container[self.random_str]:
                del CacheSession.session_container[self.random_str][key]
    
    
    conn = memcache.Client(['127.0.0.1:11210'], debug=True)
    
    class MemcachedSession():
        session_id = "__balabala__"
    
        def __init__(self,handler):
            self.handler = handler
            client_random_str = self.handler.get_cookie(MemcachedSession.session_id,None)
            if client_random_str and conn.get(client_random_str):
                self.random_str = client_random_str
            else:
                self.random_str = self.__container__random__str()
                conn.set(self.random_str,json.dumps({}),config.SESSION_EXPIRES)
    
            conn.set(self.random_str, conn.get(self.random_str), config.SESSION_EXPIRES)
    
            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
    
        def __setitem__(self,key,value):
            ret = conn.get(self.random_str)
            ret_dict = json.loads(ret)
            ret_dict[key] = value
            conn.set(self.random_str,json.dumps(ret_dict),config.SESSION_EXPIRES)
    
        def __getitem__(self,key):
            ret = conn.get(self.random_str)
            ret_dict = json.loads(ret)
            result = ret_dict.get(key,None)
            return result
    
        def __delitem__(self, key):
            ret = conn.get(self.random_str)
            ret_dict = json.loads(ret)
            del ret_dict[key]
            conn.set(self.random_str, json.dumps(ret_dict), config.SESSION_EXPIRES)
    
    
    pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
    r = redis.Redis(connection_pool=pool)
    
    class RedisSession():
        session_id = "__balabala__"
    
        def __init__(self, handler):
            self.handler = handler
            client_random_str = self.handler.get_cookie(RedisSession.session_id, None)
            if client_random_str and r.exists(client_random_str):
                self.random_str = client_random_str
            else:
                self.random_str = self.__container__random__str()
                r.hset(self.random_str, None, None)
    
            r.expire(self.random_str,config.SESSION_EXPIRES)
    
            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
    
        def __setitem__(self, key, value):
            if type(value) == dict:
                r.hset(self.random_str, key, json.dumps(value))
            else:
                r.hset(self.random_str, key, value)
    
        def __getitem__(self, key):
            ret = r.hget(self.random_str,key)
            if ret :
                ret_str = str(ret,encoding='utf-8')
                try:
                    result = json.loads(ret_str)
                except:
                    result = ret_str
                return result
            else:
                return ret
    
        def __delitem__(self, key):
            r.hdel(self.random_str, key)
    
    
    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
    session.py
    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    
    import tornado.ioloop
    import tornado.web
    
    from backend.session.session import SessionFactory
    
    class BaseHandler(tornado.web.RequestHandler):
        def initialize(self):
            self.session = SessionFactory.get_session_obj(self)
    request_handle.py
    #!/usr/bin/env python
    # -*-coding:utf-8 -*-
    
    # Session类型:cache/redis/memcached
    SESSION_TYPE = "cache"
    
    # Session超时时间(秒)
    SESSION_EXPIRES = 180
    config.py 配置文件
    分页

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

    前端:

    <div class="pagination">
             {% raw str_page%}  #展示原生html
    </div>
    前端页面

    后台Url配置:

    (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 分页类:

    class Pagiantion:
        def __init__(self,current_page,all_counts,per_num):
    
            all_page, c = divmod(all_counts, per_num)
            if c>0:
                all_page += 1
            self.all_page = all_page
    
            try:
                current_page = int(current_page)
            except:
                current_page = 1
            if current_page < 1:
                current_page = 1
            self.current_page = current_page
    
    
        def page_str(self,base_url):
            if self.all_page < 10:
                s = 1
                t = self.all_page
            else:
                if self.current_page < 7:
                    s = 1
                    t = 10
                else:
                    if self.all_page - self.current_page >= 4 :
                        s = self.current_page - 3
                        t = self.current_page + 4
                    else:
                        s = self.all_page - 6
                        t = self.all_page
            list_page = []
    
            # 上一页
            if self.current_page != 1:
                pre_page = "<a href='%s%s' class='pageedg'>上一页</a>" % (base_url, self.current_page - 1,)
                list_page.append(pre_page)
    
            # 页码生成
            # 生成 1 , ... ,
            if( self.current_page >= 7 ):
                temp = "<a class='pageNum' href='%s%s'>%s</a>" % (base_url, 1, 1)
                list_page.append(temp)
                temp = "<span class='ignore' >...</span>"
                list_page.append(temp)
    
            for i in range(s, t + 1):
                if i == self.current_page:
                    temp = "<span class='active-page' href='%s%s'>%s</span>" % (base_url,i, i)
                else:
                    temp = "<a href='%s%s' class='pageNum'>%s</a>" % (base_url , i, i)
                list_page.append(temp)
    
            # 下一页
            if self.current_page < self.all_page:
                next_page = "<a href='%s%s' class='pageedg'>下一页</a>" % (base_url, self.current_page + 1,)
                list_page.append(next_page)
    
            # 数据拼接 返回
            str_page = ''.join(list_page)   # 列表连接成为字符串
            return str_page
    Pagiantion 分页类
    /*分页*/
    .dig-page-block{
        width: 640px;
        height: 40px;
        /*border: 1px solid red;*/
        float: left;
        margin:20px 0 60px 0;
    }
    .dig-page {
        width:630px;
        height: 38px;
    }
    .dig-page a.pageNum{
        display: inline-block;
        min-width:34px;
        height: 34px;
        color: #369;
        line-height: 34px;
        text-align: center;
        border: 1px solid #e1e1e1;
        border-radius: 5px 5px;
        margin-right:6px;
        text-decoration: none;
        font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif;
    }
    .dig-page a.pageNum:hover{
        color: white;color: #fff;
        background-color: #369;
        border: 1px solid #369;
    }
    /*页码中文字体*/
    .dig-page a.pageedg{
        display: inline-block;
        width: 77px;
        height: 34px;
        color: #369;
        line-height: 34px;
        text-align: center;
        border: 1px solid #e1e1e1;
        border-radius: 5px 5px;
        margin-right:6px;
        text-decoration: none;
        font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif;
    }
    .dig-page a.pageedg:hover{
        color: #fff;
        background-color: #369;
        border: 1px solid #369;
    }
    .dig-page .ignore{
        display: inline-block;
        width: 32px;
        height: 32px;
        color: #369;
        line-height: 32px;
        text-align: center;
        margin-right:6px;
    }
    .dig-page .active-page{
        display: inline-block;
        min-width:34px;
        height: 34px;
        font-weight: 700;
        color: #333;
        line-height: 34px;
        text-align: center;
        margin-right:6px;
        font-family: "Arial","Microsoft YaHei","黑体","宋体",sans-serif;
    }
    分页标签 Css

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

    1.普通登陆验证

    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提交数据的登陆验证

    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标签

    <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;
         ..px;
        height: ..px;
        font-size: ..px;
        opacity: 0;
            z-index: 10;
    }

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

    方法一:利用iframe实现

    <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>
    <iframe id='my_iframe' name='my_iframe' src="" class="hide"></iframe>
    
    function imagechange(){
        imgupload();
    }
    // iframe图片上传
    function imgupload(){
        document.getElementById('my_iframe').onload = Testt;
        document.getElementById('my_form').target = 'my_iframe';
        document.getElementById('my_form').submit();
    }
    function Testt(ths) {
        var r = $("#my_iframe").contents().find("body").text();
        ret = JSON.parse(r);      // 获得后台返回的数据...
    }
    View Code

    抽屉网实现,完整代码:

    //图片上传按钮:
    $(".a-upload").on("change","input[type='file']",function(){
        imgupload()
    });
    // iframe图片上传
    function imgupload(){
        document.getElementById('my_iframe').onload = Testt;
        document.getElementById('my_form').target = 'my_iframe';
        document.getElementById('my_form').submit();
    }
    function Testt(ths) {
        var r = $("#my_iframe").contents().find("body").text();
        ret = JSON.parse(r);
        if( ret.status ){
            var img_path = ret['message']['file_path'];
            console.log(img_path);
            var pre = 'http://localhost:8888/';
            $('.img-alt').addClass('hide');
            $('.upload-btn').addClass('upload-btn-show');
            $('.upload-show').removeClass('hide').attr('src',pre+img_path);
            $(".upload-error").text('');
        }else{
            $.each(ret['message'],function (k,v) {
                $(".upload-error").text(v).show();
                console.log(v);
                //清除信息:
                $('#uploadimage').val('');
                $(".img-alt").text("支持jpg、jpeg、gif、png格式,且不超过5MB");
                $(".upload-error").text("您上传的图片格式不合法,请重新上传").show();
                return false;
            });
        }
    }
    jQ 代码
    <div class="img-upload-block">
        <img src="" alt="" class="upload-show hide"/>
        <div class="upload-btn">
            <a href="javascript:;" class="a-upload">上传
                <input type="file" name="uploadimage" id="uploadimage">
            </a>
        </div>
        <span class="img-alt">支持jpg、jpeg、gif、png格式,且不超过5MB</span>
    </div>
    Html 代码
    /*上传文件按钮*/
    .a-upload {
        position: relative;
        display: inline-block;
        background: url('http://dig.chouti.com/images/bottom.png?v=2.8')no-repeat center center;
        background-position: 0 0px;
        border-radius: 4px;
        padding: 4px 16px;
        overflow: hidden;
        color: white;
        font-weight: 700;
        text-decoration: none;
        text-indent: 0;
        line-height: 20px;
        margin: 10px 0 0 6px;
    }
    .a-upload input {
        position: absolute;
        right: 0;
        top: 0;
        opacity: 0;
    }
    .a-upload:hover {
        color: white;
        background-position: 0 -33px;
        text-decoration: none;
    }
    .pic-content .img-upload-block .img-alt{
        color: #8ca1c1;
        padding-left: 6px;
        vertical-align: -12px;
        margin-left: 4px;
        font-size: 12px;
        font-family: "5b8b4f53";
    }
    Css 代码

    方法二:ajax实现

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

    <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);
    	}
    })
    

      

      

  • 相关阅读:
    嵌入式GUI FTK介绍(11)交叉编译
    3G手机 。Android 。Broncho
    PXA300/310的2D图形加速示例代码
    在终端下修改Android手机(Broncho A1)的系统设置
    FTK google group开通,欢迎加入交流。
    使用WebDeployment Project改善VS2005发布网站问题
    IIS 伪静态设置
    使用jQuery简化Ajax开发——Ajax开发入门[令狐葱翻译版part1]
    web.config文件中的特殊字符处理
    网上找的asp.net伪静态教程,大晚上补补课
  • 原文地址:https://www.cnblogs.com/5poi/p/6622613.html
Copyright © 2020-2023  润新知