咱們知道,平時在登錄某個網站或軟件時,網站對於你輸入的內容是有要求的,而且會對你輸入的錯誤內容有提示,對於Django這種大而全的web框架,是提供了form表單驗證功能,可是對於Tornado而言,就沒有這功能,因此就須要咱們來本身自定義form表單驗證,並且這種方法正是Django裏的form表單驗證的實質內容,也幫咱們在後面學習Django理解相關的源碼。javascript
寫以前,咱們必須知道form表單驗證的實質是什麼?html
咱們知道用戶提交數據是經過post方式提交,因此咱們重寫post方法,並在post方法進行業務邏輯處理前端
寫以前,咱們必須知道form表單驗證的實質是什麼?java
咱們知道用戶提交數據是經過post方式提交,因此咱們重寫post方法,並在post方法進行業務邏輯處理python
class MainForm(object):
def __init__(self):
# 各類信息正則匹配規則
# 而且要求這裏字段名和前端傳來的name一致
self.host = "(.*)"
self.ip = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$"
self.port = '(\d+)'
self.phone = '^1[3|4|5|8][0-9]\d{8}$'
def check_valid(self, request):
flag = True
form_dict = self.__dict__ #獲取類的普通字段和值
for key, regular in form_dict.items():
post_value = request.get_argument(key) #獲取用戶輸入的值
# 讓提交的數據 和 定義的正則表達式進行匹配
ret = re.match(regular, post_value)
print key,ret,post_value
if not ret:
flag = False #一旦有匹配不成功的,設置爲False
return flag #post方法里根據這個返回值來決定給客戶返回什麼內容
class IndexHandler(BaseRequestHandler): def get(self): self.render('index.html') def post(self,*args,**kwargs): obj = MainForm() obj.check_valid(self) self.get_argument()
所以咱們應將自定義form中的自定義字段根據不一樣的正則表達式拆分紅跟本身屬性相關的類,實例以下:jquery
根據每一個字段的特性,定義基礎的字段,如字符串,郵件類型,整數類等web
class InputText: def __str__(self): return '<input type="text" />' class InputPassword: def __str__(self): return '<input type="password" />' class StringField: reg = "^\w+$" def __init__(self,w=None): self.w = w if w else InputText() def match(self): pass def __str__(self): return str(self.w)
基於基本的字段,定製基礎form類ajax
class IndexForm: def __init__(self): self.user = StringField() self.pwd = StringField(w=InputPassword()) def is_valid(self,handler):#handler 爲tornado中路由對應的處理類的實例化對象 flag = True for k,v in self.__dict__.items(): # k="user" v="^\w+$" StringField對象 # k="pwd" v="^\w+$" EmailField對象 if type(v) == StringListField: input_value = handler.get_arguments(k) else: input_value = handler.get_argument(k) result = v.match(input_value) if not result: flag = False return flag
自定義Form完整式例以下:正則表達式
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web import re class InputText: def __str__(self): return '<input type="text" />' class InputPassword: def __str__(self): return '<input type="password" />' class StringField: reg = "^\w+$" def __init__(self,w=None): self.w = w if w else InputText() def match(self): pass def __str__(self): return str(self.w) class StringListField: reg = "^\w+$" def __init__(self): pass def match(self): pass class EmailField: reg = "^\w+$" def __init__(self): pass class IndexForm: def __init__(self): self.user = StringField() self.pwd = StringField(w=InputPassword()) def is_valid(self,handler): flag = True for k,v in self.__dict__.items(): # k="user" v="^\w+$" StringField對象 # k="pwd" v="^\w+$" EmailField對象 if type(v) == StringListField: input_value = handler.get_arguments(k) else: input_value = handler.get_argument(k) result = v.match(input_value) if not result: flag = False return flag class IndexHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): form = IndexForm() self.render('index.html', form=form) def post(self, *args, **kwargs): form = IndexForm() ret = form.is_valid(self) print(ret) settings = { 'template_path': 'views' } application = tornado.web.Application([ (r"/index.html", IndexHandler), ], **settings) if __name__ == "__main__": print('http://127.0.0.1:8005') application.listen(8005) tornado.ioloop.IOLoop.instance().start()
經過以上的實例咱們再來看下Tyrion開源的自定製Form 是如何開發的redis
1.首先定義一個基礎的Field類
import re
from Tyrion import Widget
from Tyrion.Framework import FrameworkFactory
class Field:
"""
全部Form字段的基類
"""
def __init__(self, widget):
self.status = False
self.name = None
self.value = None
self.error = None
self.widget = widget
def valid(self, handler):
"""
字段必須實現該方法,用於從請求中獲取用戶輸入的值並和規則進行比較
:param handler: Tornado處理請求的XXXHandler對象
:return:
"""
raise NotImplementedError('your class %s must implement valid method' % self.__class__)
def __str__(self):
if self.value == None:
return str(self.widget)
if isinstance(self.widget, Widget.SingleSelect):
self.widget.selected_value = self.value
elif isinstance(self.widget, Widget.MultiSelect):
self.widget.selected_value_list = self.value
elif isinstance(self.widget, Widget.InputSingleCheckBox):
self.widget.attr['checked'] = 'checked'
elif isinstance(self.widget, Widget.InputMultiCheckBox):
self.widget.checked_value_list = self.value
elif isinstance(self.widget, Widget.InputRadio):
self.widget.checked_value = self.value
elif isinstance(self.widget, Widget.TextArea):
self.widget.value = self.value
else:
self.widget.attr['value'] = self.value
return str(self.widget)
def set_value(self, value):
self.value = value
2.基於Field定義派生類如EmailField,IpField,IntegerField
class StringField(Field): """ 字符串類字段 """ REGULAR = "^.*$" DEFAULT_WIDGET = Widget.InputText def __init__(self, max_length=None, min_length=None, error=None, required=True, widget=None): """ :param error: 自定義錯誤信息 如:{ 'required': '值爲空時的錯誤提示', 'invalid': '格式錯誤時的錯誤提示', 'max_length': '最大長度爲10', 'min_length': '最小長度爲1', } :param required: 是否必須 :param widget: 指定插件,用於生成HTML標籤(默認生成Input標籤) :return: """ self.custom_error_dict = {} if error: self.custom_error_dict.update(error) self.required = required self.max_length = max_length self.min_length = min_length widget = widget if widget else self.DEFAULT_WIDGET() super(StringField, self).__init__(widget) def valid(self, handler): """ 從請求中獲取用戶輸入的值並和規則進行比較 :param handler: Tornado處理請求的XXXHandler對象 :return: """ input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None) # input_value = handler.get_argument(self.name, None) self.value = input_value if not input_value: if not self.required: self.status = True return if self.custom_error_dict.get('required', None): self.error = self.custom_error_dict['required'] else: self.error = "%s is required" % self.name return ret = re.match(self.REGULAR, input_value) if not ret: if self.custom_error_dict.get('invalid', None): self.error = self.custom_error_dict['invalid'] else: self.error = "%s is invalid" % self.name return if self.max_length: if len(input_value) > self.max_length: if self.custom_error_dict.get('max_length', None): self.error = self.custom_error_dict['max_length'] else: self.error = "%s max length is %s" % (self.name, self.max_length) return if self.min_length: if len(input_value) < self.min_length: if self.custom_error_dict.get('min_length', None): self.error = self.custom_error_dict['min_length'] else: self.error = "%s min length is %s" % (self.name, self.min_length) return self.status = True class EmailField(Field): """ 字符串類字段 """ REGULAR = "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$" DEFAULT_WIDGET = Widget.InputText def __init__(self, max_length=None, min_length=None, error=None, required=True, widget=None): """ :param error: 自定義錯誤信息 如:{ 'required': '值爲空時的錯誤提示', 'invalid': '格式錯誤時的錯誤提示', 'max_length': '最大長度爲10', 'min_length': '最小長度爲1', } :param required: 是否必須 :param widget: 指定插件,用於生成HTML標籤(默認生成Input標籤) :return: """ self.custom_error_dict = {} if error: self.custom_error_dict.update(error) self.required = required self.max_length = max_length self.min_length = min_length widget = widget if widget else self.DEFAULT_WIDGET() super(EmailField, self).__init__(widget) def valid(self, handler): """ 從請求中獲取用戶輸入的值並和規則進行比較 :param handler: Tornado處理請求的XXXHandler對象 :return: """ input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None) # input_value = handler.get_argument(self.name, None) self.value = input_value if not input_value: if not self.required: self.status = True return if self.custom_error_dict.get('required', None): self.error = self.custom_error_dict['required'] else: self.error = "%s is required" % self.name return ret = re.match(self.REGULAR, input_value) if not ret: if self.custom_error_dict.get('invalid', None): self.error = self.custom_error_dict['invalid'] else: self.error = "%s is invalid" % self.name return if self.max_length: if len(input_value) > self.max_length: if self.custom_error_dict.get('max_length', None): self.error = self.custom_error_dict['max_length'] else: self.error = "%s max length is %s" % (self.name, self.max_length) return if self.min_length: if len(input_value) < self.max_length: if self.custom_error_dict.get('min_length', None): self.error = self.custom_error_dict['min_length'] else: self.error = "%s min length is %s" % (self.name, self.min_length) return self.status = True class IPField(Field): """ 字符串類字段 """ REGULAR = "^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$" DEFAULT_WIDGET = Widget.InputText def __init__(self, max_length=None, min_length=None, error=None, required=True, widget=None): """ :param error: 自定義錯誤信息 如:{ 'required': '值爲空時的錯誤提示', 'invalid': '格式錯誤時的錯誤提示', 'max_length': '最大長度爲10', 'min_length': '最小長度爲1', } :param required: 是否必須 :param widget: 指定插件,用於生成HTML標籤(默認生成Input標籤) :return: """ self.custom_error_dict = {} if error: self.custom_error_dict.update(error) self.required = required self.max_length = max_length self.min_length = min_length widget = widget if widget else self.DEFAULT_WIDGET() super(IPField, self).__init__(widget) def valid(self, handler): """ 從請求中獲取用戶輸入的值並和規則進行比較 :param handler: Tornado處理請求的XXXHandler對象 :return: """ input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None) # input_value = handler.get_argument(self.name, None) self.value = input_value if not input_value: if not self.required: self.status = True return if self.custom_error_dict.get('required', None): self.error = self.custom_error_dict['required'] else: self.error = "%s is required" % self.name return ret = re.match(self.REGULAR, input_value) if not ret: if self.custom_error_dict.get('invalid', None): self.error = self.custom_error_dict['invalid'] else: self.error = "%s is invalid" % self.name return if self.max_length: if len(input_value) > self.max_length: if self.custom_error_dict.get('max_length', None): self.error = self.custom_error_dict['max_length'] else: self.error = "%s max length is %s" % (self.name, self.max_length) return if self.min_length: if len(input_value) < self.max_length: if self.custom_error_dict.get('min_length', None): self.error = self.custom_error_dict['min_length'] else: self.error = "%s min length is %s" % (self.name, self.min_length) return self.status = True class IntegerField(Field): """ 字符串類字段 """ REGULAR = "^\d+$" DEFAULT_WIDGET = Widget.InputText def __init__(self, max_value=None, min_value=None, error=None, required=True, widget=None): """ :param error: 自定義錯誤信息 如:{ 'required': '值爲空時的錯誤提示', 'invalid': '格式錯誤時的錯誤提示', 'max_length': '最大值爲10', 'min_length': '最小值度爲1', } :param required: 是否必須 :param widget: 指定插件,用於生成HTML標籤(默認生成Input標籤) :return: """ self.custom_error_dict = {} if error: self.custom_error_dict.update(error) self.required = required self.max_value = max_value self.min_value = min_value widget = widget if widget else self.DEFAULT_WIDGET() super(IntegerField, self).__init__(widget) def valid(self, handler): """ 從請求中獲取用戶輸入的值並和規則進行比較 :param handler: Tornado處理請求的XXXHandler對象 :return: """ input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None) # input_value = handler.get_argument(self.name, None) self.value = input_value if not input_value: if not self.required: self.status = True return if self.custom_error_dict.get('required', None): self.error = self.custom_error_dict['required'] else: self.error = "%s is required" % self.name return ret = re.match(self.REGULAR, input_value) if not ret: if self.custom_error_dict.get('invalid', None): self.error = self.custom_error_dict['invalid'] else: self.error = "%s is invalid" % self.name return input_value = int(input_value) self.value = input_value if self.max_value: if input_value > self.max_value: if self.custom_error_dict.get('max_value', None): self.error = self.custom_error_dict['max_value'] else: self.error = "%s max value is %s" % (self.name, self.max_value) return if self.min_value: if input_value < self.min_value: if self.custom_error_dict.get('min_value', None): self.error = self.custom_error_dict['min_value'] else: self.error = "%s min value is %s" % (self.name, self.min_value) return self.status = True class FloatField(Field): """ 字符串類字段 """ REGULAR = "^\d+(\.\d{1,2})?$" DEFAULT_WIDGET = Widget.InputText def __init__(self, max_value=None, min_value=None, error=None, required=True, widget=None): """ :param error: 自定義錯誤信息 如:{ 'required': '值爲空時的錯誤提示', 'invalid': '格式錯誤時的錯誤提示', 'max_length': '最大值爲10', 'min_length': '最小值度爲1', } :param required: 是否必須 :param widget: 指定插件,用於生成HTML標籤(默認生成Input標籤) :return: """ self.custom_error_dict = {} if error: self.custom_error_dict.update(error) self.required = required self.max_value = max_value self.min_value = min_value widget = widget if widget else self.DEFAULT_WIDGET() super(FloatField, self).__init__(widget) def valid(self, handler): """ 從請求中獲取用戶輸入的值並和規則進行比較 :param handler: Tornado處理請求的XXXHandler對象 :return: """ input_value = FrameworkFactory.get_framework().get_argument(handler, self.name, None) # input_value = handler.get_argument(self.name, None) self.value = input_value if not input_value: if not self.required: self.status = True return if self.custom_error_dict.get('required', None): self.error = self.custom_error_dict['required'] else: self.error = "%s is required" % self.name return ret = re.match(self.REGULAR, input_value) if not ret: if self.custom_error_dict.get('invalid', None): self.error = self.custom_error_dict['invalid'] else: self.error = "%s is invalid" % self.name return input_value = float(input_value) self.value = input_value if self.max_value: if input_value > self.max_value: if self.custom_error_dict.get('max_value', None): self.error = self.custom_error_dict['max_value'] else: self.error = "%s max value is %s" % (self.name, self.max_value) return if self.min_value: if input_value < self.min_value: if self.custom_error_dict.get('min_value', None): self.error = self.custom_error_dict['min_value'] else: self.error = "%s min value is %s" % (self.name, self.min_value) return self.status = True class StringListField(Field): """ 字符串類字段 """ REGULAR = "^.*$" DEFAULT_WIDGET = Widget.InputMultiCheckBox def __init__(self, ele_max_length=None, ele_min_length=None, error=None, required=True, widget=None): """ :param error: 自定義錯誤信息 如:{ 'required': '值爲空時的錯誤提示', 'element': '列表中的元素必須是字符串', 'ele_max_length': '最大長度爲10', 'ele_min_length': '最小長度爲1', } :param required: 是否必須 :param widget: 指定插件,用於生成HTML標籤(默認生成Input標籤) :return: """ self.custom_error_dict = {} if error: self.custom_error_dict.update(error) self.required = required self.ele_max_length = ele_max_length self.ele_min_length = ele_min_length widget = widget if widget else self.DEFAULT_WIDGET() super(StringListField, self).__init__(widget) def valid(self, handler): """ 從請求中獲取用戶輸入的值並和規則進行比較 :param handler: Tornado處理請求的XXXHandler對象 :return: """ input_value = FrameworkFactory.get_framework().get_arguments(handler, self.name, []) # input_value = handler.get_arguments(self.name) self.value = input_value if not input_value: if not self.required: self.status = True return if self.custom_error_dict.get('required', None): self.error = self.custom_error_dict['required'] else: self.error = "%s is required" % self.name return for value in input_value: ret = re.match(self.REGULAR, value) if not ret: if self.custom_error_dict.get('element', None): self.error = self.custom_error_dict['element'] else: self.error = "element %s is invalid" % self.name return if self.ele_max_length: if len(value) > self.ele_max_length: if self.custom_error_dict.get('ele_max_length', None): self.error = self.custom_error_dict['ele_max_length'] else: self.error = "element %s max length is %s" % (self.name, self.ele_max_length) return if self.ele_min_length: if len(value) < self.ele_min_length: if self.custom_error_dict.get('ele_min_length', None): self.error = self.custom_error_dict['ele_min_length'] else: self.error = "element %s min length is %s" % (self.name, self.ele_min_length) return self.status = True class IntegerListField(Field): """ 字符串類字段 """ REGULAR = "^\d+$" DEFAULT_WIDGET = Widget.InputMultiCheckBox def __init__(self, ele_max_value=None, ele_min_value=None, error=None, required=True, widget=None): """ :param error: 自定義錯誤信息 如:{ 'required': '值爲空時的錯誤提示', 'element': '列表中的元素必須是數字', 'ele_max_value': '最大值爲x', 'ele_min_value': '最小值爲x', } :param required: 是否必須 :param widget: 指定插件,用於生成HTML標籤(默認生成Input標籤) :return: """ self.custom_error_dict = {} if error: self.custom_error_dict.update(error) self.required = required self.ele_max_value = ele_max_value self.ele_min_value = ele_min_value widget = widget if widget else self.DEFAULT_WIDGET() super(IntegerListField, self).__init__(widget) def valid(self, handler): """ 從請求中獲取用戶輸入的值並和規則進行比較 :param handler: Tornado處理請求的XXXHandler對象 :return: """ input_value = FrameworkFactory.get_framework().get_arguments(handler, self.name, []) # input_value = handler.get_arguments(self.name) self.value = input_value if not input_value: if not self.required: self.status = True return if self.custom_error_dict.get('required', None): self.error = self.custom_error_dict['required'] else: self.error = "%s is required" % self.name return success_value_list = [] for value in input_value: ret = re.match(self.REGULAR, value) if not ret: if self.custom_error_dict.get('element', None): self.error = self.custom_error_dict['element'] else: self.error = "element %s is invalid" % self.name return value = int(value) success_value_list.append(value) if self.ele_max_value: if value > self.ele_max_value: if self.custom_error_dict.get('ele_max_value', None): self.error = self.custom_error_dict['ele_max_value'] else: self.error = "element %s max value is %s" % (self.name, self.ele_max_value) return if self.ele_min_value: if value < self.ele_min_value: if self.custom_error_dict.get('ele_min_value', None): self.error = self.custom_error_dict['ele_min_value'] else: self.error = "element %s min value is %s" % (self.name, self.ele_min_value) return self.value = success_value_list self.status = True
3.咱們發現上面定義的子Field中包含widget,這個是根據不一樣的Filed的需求生成不一樣的html標籤。具體代碼以下:
#!/usr/bin/env python # -*- coding:utf-8 -*- class Input: def __init__(self, attr=None): """ :param attr: 生成的HTML屬性,如:{'id': '123'} :return: """ self.attr = attr if attr else {} def __str__(self): """ 使用對象時返回的字符串 :return: """ t = "<input %s />" attr_list = [] for k, v in self.attr.items(): temp = "%s='%s' " % (k, v,) attr_list.append(temp) tag = t % (''.join(attr_list)) return tag class InputText(Input): def __init__(self, attr=None): attr_dict = {'type': 'text'} if attr: attr_dict.update(attr) super(InputText, self).__init__(attr_dict) class InputEmail(Input): def __init__(self, attr=None): attr_dict = {'type': 'email'} if attr: attr_dict.update(attr) super(InputEmail, self).__init__(attr_dict) class InputPassword(Input): def __init__(self, attr=None): attr_dict = {'type': 'password'} if attr: attr_dict.update(attr) super(InputPassword, self).__init__(attr_dict) class InputSingleCheckBox(Input): def __init__(self, attr=None): attr_dict = {'type': 'checkbox'} if attr: attr_dict.update(attr) super(InputSingleCheckBox, self).__init__(attr_dict) def __str__(self): """ 使用對象時返回的字符串 :return: """ t = "<input %s />" attr_list = [] for k, v in self.attr.items(): temp = "%s='%s' " % (k, v,) attr_list.append(temp) tag = t % (''.join(attr_list)) return tag class InputMultiCheckBox: def __init__(self, attr=None, text_value_list=None, checked_value_list=None): """ :param attr: 生成的HTML屬性,如:{'id': '123'} :param text_value_list: 生成CheckBox的value和內容,如: [ {'value':1, 'text': '籃球'}, {'value':2, 'text': '足球'}, {'value':3, 'text': '乒乓球'}, {'value':4, 'text': '羽毛球'}, ] :param checked_value_list: 被選中的checked_value_list,如:[2,3] :return: """ attr_dict = {'type': 'checkbox'} if attr: attr_dict.update(attr) self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else [] self.checked_value_list = checked_value_list if checked_value_list else [] def __str__(self): """ 使用對象時返回的字符串 :return: """ tag_list = [] for item in self.text_value_list: a = "<div><span>%s</span><span>%s</span></div>" b = "<input %s />" attr_list = [] for k, v in self.attr.items(): temp = "%s='%s' " % (k, v,) attr_list.append(temp) attr_list.append("%s='%s' " % ('value', item['value'])) if item['value'] in self.checked_value_list: attr_list.append("checked='checked' ") input_tag = b % (''.join(attr_list)) c = a % (input_tag, item['text'], ) tag_list.append(c) return ''.join(tag_list) class InputRadio: def __init__(self, attr=None, text_value_list=None, checked_value=None): """ :param attr: 生成的HTML屬性,如:{'id': '123'} :param text_value_list: 生成CheckBox的value和內容,如: [ {'value':1, 'text': '籃球'}, {'value':2, 'text': '足球'}, {'value':3, 'text': '乒乓球'}, {'value':4, 'text': '羽毛球'}, ] :param checked_value: 被選中的checked_value,如:2 :return: """ attr_dict = {'type': 'radio'} if attr: attr_dict.update(attr) self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else [] self.checked_value = checked_value def __str__(self): """ 使用對象時返回的字符串 :return: """ tag_list = [] for item in self.text_value_list: a = "<div><span>%s</span><span>%s</span></div>" b = "<input %s />" attr_list = [] for k, v in self.attr.items(): temp = "%s='%s' " % (k, v,) attr_list.append(temp) attr_list.append("%s='%s' " % ('value', item['value'])) if item['value'] == self.checked_value: attr_list.append("checked='checked' ") input_tag = b % (''.join(attr_list)) c = a % (input_tag,item['text']) tag_list.append(c) return ''.join(tag_list) class SingleSelect: def __init__(self, attr=None, text_value_list=None, selected_value=None): """ :param attr: 生成的HTML屬性,如:{'id': '123'} :param text_value_list: 生成CheckBox的value和內容,如: [ {'value':1, 'text': '籃球'}, {'value':2, 'text': '足球'}, {'value':3, 'text': '乒乓球'}, {'value':4, 'text': '羽毛球'}, ] :param selected_value: 被選中的checked_value,如:2 :return: """ attr_dict = {} if attr: attr_dict.update(attr) self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else [] self.selected_value = selected_value def __str__(self): """ 使用對象時返回的字符串 :return: """ a = "<select %s>%s</select>" attr_list = [] for k, v in self.attr.items(): temp = "%s='%s' " % (k, v,) attr_list.append(temp) option_list = [] for item in self.text_value_list: if item['value'] == self.selected_value: b = "<option selected='selected' value='%s'>%s</option>" else: b = "<option value='%s'>%s</option>" option = b % (item['value'], item['text'],) option_list.append(option) tag = a % (''.join(attr_list), ''.join(option_list)) return tag class MultiSelect: def __init__(self, attr=None, text_value_list=None, selected_value_list=None): """ :param attr: 生成的Select標籤的屬性,如:{'id': '123'} :param text_value_list: 生成CheckBox的value和內容,如: [ {'value':1, 'text': '籃球'}, {'value':2, 'text': '足球'}, {'value':3, 'text': '乒乓球'}, {'value':4, 'text': '羽毛球'}, ] :param selected_value_list: selected_value_list,如:[2,3,4] :return: """ attr_dict = {'multiple': 'multiple'} if attr: attr_dict.update(attr) self.attr = attr_dict self.text_value_list = text_value_list if text_value_list else [] self.selected_value_list = selected_value_list if selected_value_list else [] def __str__(self): """ 使用對象時返回的字符串 :return: """ a = "<select %s>%s</select>" attr_list = [] for k, v in self.attr.items(): temp = "%s='%s' " % (k, v,) attr_list.append(temp) option_list = [] for item in self.text_value_list: if item['value'] in self.selected_value_list: b = "<option selected='selected' value='%s'>%s</option>" else: b = "<option value='%s'>%s</option>" option = b % (item['value'], item['text'],) option_list.append(option) tag = a % (''.join(attr_list), ''.join(option_list)) return tag class TextArea: def __init__(self, attr=None, value=""): """ :param attr: 生成的HTML屬性,如:{'id': '123'} :return: """ self.attr = attr if attr else {} self.value = value def __str__(self): """ 使用對象時返回的字符串 :return: """ t = "<textarea %s>%s</textarea>" attr_list = [] for k, v in self.attr.items(): temp = "%s='%s' " % (k, v,) attr_list.append(temp) tag = t % (''.join(attr_list), self.value) return tag
下面是具體的使用方法:
一、下載安裝
pip install PyTyrion
二、配置WEB框架種類
因爲Tyrion同時支持Tornado、Django、Flask、Bottle多個WEB框架,全部在使用前須要進行指定。
import Tyrion Tyrion.setup('tornado') # setup的參數有:tornado(默認)、django、bottle、flask
三、建立Form類
Form類用於提供驗證規則、插件屬性、錯誤信息等
from Tyrion.Forms import Form from Tyrion.Fields import StringField from Tyrion.Fields import EmailField class LoginForm(Form): username = StringField(error={'required': '用戶名不能爲空'}) password = StringField(error={'required': '密碼不能爲空'}) email = EmailField(error={'required': '郵箱不能爲空', 'invalid': '郵箱格式錯誤'})
四、驗證用戶請求
前端HTML代碼:
<form method="POST" action="/login.html"> <div> <input type="text" name="username"> </div> <div> <input type="text" name="password"> </div> <div> <input type="text" name="email"> </div> <input type="submit" value="提交"> </form>
用戶提交數據時,在後臺書寫以下代碼便可實現用戶請求數據驗證(Tornado示例):
class LoginHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.render('login.html') def post(self, *args, **kwargs): form = LoginForm(self) ###### 檢查用戶輸入是否合法 ###### if form.is_valid(): ###### 若是不合法,則輸出錯誤信息 ###### print(form.error_dict) else: ###### 若是合法,則輸出用戶輸入的內容 ######
五、驗證用戶請求 && 生成HTML標籤 && 保留上次輸入內容 && 錯誤提示
Tyrion不只能夠驗證用戶請求,還能夠生成自動建立HTML標籤而且能夠保留用戶上次輸入的內容。在HTML模板中調用Form類對象的字段便可,如(Tornado示例):
from Tyrion.Forms import Form
from Tyrion.Fields import StringField
from Tyrion.Fields import EmailField
class LoginForm(Form):
username = StringField(error={'required': '用戶名不能爲空'})
password = StringField(error={'required': '密碼不能爲空'})
email = EmailField(error={'required': '郵箱不能爲空', 'invalid': '郵箱格式錯誤'})
class LoginHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
form = LoginForm(self)
self.render('login.html', form=form)
def post(self, *args, **kwargs):
form = LoginForm(self)
print(form.is_valid())
print(form.error_dict)
print(form.value_dict)
self.render('login.html', form=form)
<form method="post" action="/login.html"> <div> <!-- Form建立的標籤 --> {% raw form.username %} <!-- 錯誤信息 --> <span>{{form.error_dict.get('username',"")}}</span> </div> <div> {% raw form.password %} <span>{{form.error_dict.get('password',"")}}</span> </div> <div> {% raw form.email %} <span>{{form.error_dict.get('email',"")}}</span> </div> <input type="submit" value="提交"/> </form>
六、Form字段類型
Form的字段用於指定從請求中獲取的數據類型以及格式,以此來驗證用戶輸入的內容。
from Tyrion.Forms import Form from Tyrion.Fields import StringField from Tyrion.Fields import EmailField class LoginForm(Form): username = StringField(error={'required': '用戶名不能爲空'}) password = StringField(error={'required': '密碼不能爲空'}) email = EmailField(error={'required': '郵箱不能爲空', 'invalid': '郵箱格式錯誤'})
以上代碼表示此Form類能夠用於驗證用戶輸入的內容,而且 username和password必須不能爲空,email必須不能爲空而且必須是郵箱格式。
目前支持全部字段:
StringField
"""
要求必須是字符串,即:正則^.*$
參數:
required 布爾值,是否容許爲空
max_length 整數,限制用戶輸入內容最大長度
min_length 整數,限制用戶輸入內容最小長度
error 字典,自定義錯誤提示,如:{
'required': '值爲空時的錯誤提示',
'invalid': '格式錯誤時的錯誤提示',
'max_length': '最大長度爲10',
'min_length': '最小長度爲1',
}
widget 定製生成的HTML插件(默認InputText)
"""
EmailField
"""
要求必須是郵箱格式的字符串
參數:
required 布爾值,是否容許爲空
max_length 整數,限制用戶輸入內容最大長度
min_length 整數,限制用戶輸入內容最小長度
error 字典,自定義錯誤提示,如:{
'required': '值爲空時的錯誤提示',
'invalid': '格式錯誤時的錯誤提示',
'max_length': '最大長度爲10',
'min_length': '最小長度爲1',
}
widget 定製生成的HTML插件(默認InputText)
"""
IPField
"""
要求必須是IP格式
參數:
required 布爾值,是否容許爲空
max_length 整數,限制用戶輸入內容最大長度
min_length 整數,限制用戶輸入內容最小長度
error 字典,自定義錯誤提示,如:{
'required': '值爲空時的錯誤提示',
'invalid': '格式錯誤時的錯誤提示',
'max_length': '最大長度爲10',
'min_length': '最小長度爲1',
}
widget 定製生成的HTML插件(默認InputText)
"""
IntegerField
"""
要求必須整數格式
參數:
required 布爾值,是否容許爲空
max_value 整數,限制用戶輸入數字最大值
min_value 整數,限制用戶輸入數字最小值
error 字典,自定義錯誤提示,如:{
'required': '值爲空時的錯誤提示',
'invalid': '格式錯誤時的錯誤提示',
'max_value': '最大值爲10',
'max_value': '最小值度爲1',
}
widget 定製生成的HTML插件(默認InputText)
"""
FloatField
"""
要求必須小數格式
參數:
required 布爾值,是否容許爲空
max_value 整數,限制用戶輸入數字最大值
min_value 整數,限制用戶輸入數字最小值
error 字典,自定義錯誤提示,如:{
'required': '值爲空時的錯誤提示',
'invalid': '格式錯誤時的錯誤提示',
'max_value': '最大值爲10',
'max_value': '最小值度爲1',
}
widget 定製生成的HTML插件(默認InputText)
"""
StringListField
"""
用於獲取請求中的多個值,且保證每個元素是字符串,即:正則^.*$
如:checkbox或selct多選時,會提交多個值,用此字段能夠將用戶提交的值保存至列表
參數:
required 布爾值,是否容許爲空
ele_max_length 整數,限制用戶輸入的每一個元素內容最大長度
ele_min_length 整數,限制用戶輸入的每一個元素內容最小長度
error 字典,自定義錯誤提示,如:{
'required': '值爲空時的錯誤提示',
'element': '列表中的元素必須是字符串',
'ele_max_length': '最大長度爲10',
'ele_min_length': '最小長度爲1',
}
widget 定製生成的HTML插件(默認InputMultiCheckBox,即:checkbox)
"""
IntegerListField
"""
用於獲取請求中的多個值,且保證每個元素是整數
如:checkbox或selct多選時,會提交多個值,用此字段能夠將用戶提交的值保存至列表
參數:
required 布爾值,是否容許爲空
ele_max_value 整數,限制用戶輸入的每一個元素內容最大長度
ele_min_value 整數,限制用戶輸入的每一個元素內容最小長度
error 字典,自定義錯誤提示,如:{
'required': '值爲空時的錯誤提示',
'element': '列表中的元素必須是數字',
'ele_max_value': '最大值爲x',
'ele_min_value': '最小值爲x',
}
widget 定製生成的HTML插件(默認InputMultiCheckBox,即:checkbox)
"""
七、Form字段widget參數:HTML插件
HTML插件用於指定當前字段在生成HTML時表現的種類和屬性,經過指定此參數從而實現定製頁面上生成的HTML標籤
from Tyrion.Forms import Form from Tyrion.Fields import StringField from Tyrion.Fields import EmailField from Tyrion.Widget import InputPassword class LoginForm(Form): password = StringField(error={'required': '密碼不能爲空'},widget=InputPassword())
上述LoginForm的password字段要求用戶輸入必須是字符串類型,而且指定生成HTML標籤時會建立爲<input type='password' > 標籤
目前支持全部插件:
InputText """ 設置Form對應字段在HTML中生成input type='text' 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1', 'placeholder': 'username'} """ InputEmail """ 設置Form對應字段在HTML中生成input type='email' 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1', 'placeholder': 'username'} """ InputPassword """ 設置Form對應字段在HTML中生成input type='password' 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1', 'placeholder': 'username'} """ TextArea """ 設置Form對應字段在HTML中生成 textarea 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1'} value 字符串,用於設置textarea標籤中默認顯示的內容 """ InputRadio """ 設置Form對應字段在HTML中生成一系列 input type='radio' 標籤(選擇時互斥) 參數: attr 字典,生成的HTML屬性,如:{'class': 'c1'} text_value_list 列表,生成的多個radio標籤的內容和值,如:[ {'value':1, 'text': '男'}, {'value':2, 'text': '女'}, ] checked_value 整數或字符串,默認被選中的標籤的value的值 示例: from Tyrion.Forms import Form from Tyrion.Fields import IntegerField from Tyrion.Widget import InputRadio class LoginForm(Form): favor = IntegerField(error={'required': '愛好不能爲空'}, widget=InputRadio(attr={'class': 'c1'}, text_value_list=[ {'value': 1, 'text': '男'}, {'value': 2, 'text': '女'}, ], checked_value=2 ) ) 上述favor字段生成的HTML標籤爲: <div> <span> <input class='c1' type="radio" name="gender" value="1"> </span> <span>男</span> </div> <div> <span> <input class='c1' type="radio" name="gender" value="2" checked='checked'> </span> <span>女</span> </div> """ InputSingleCheckBox """ 設置Form對應字段在HTML中生成 input type='checkbox' 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1'} """ InputMultiCheckBox """ 設置Form對應字段在HTML中生成一系列 input type='checkbox' 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1'} text_value_list 列表,生成的多個checkbox標籤的內容和值,如:[ {'value':1, 'text': '籃球'}, {'value':2, 'text': '足球'}, {'value':3, 'text': '乒乓球'}, {'value':4, 'text': '羽毛球'}, ] checked_value_list 列表,默認選中的標籤對應的value, 如:[1,3] """ SingleSelect """ 設置Form對應字段在HTML中生成 單選select 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1'} text_value_list 列表,用於指定select標籤中的option,如:[ {'value':1, 'text': '北京'}, {'value':2, 'text': '上海'}, {'value':3, 'text': '廣州'}, {'value':4, 'text': '重慶'}, ] selected_value 數字或字符串,默認被選中選項對應的值,如: 3 """ MultiSelect """ 設置Form對應字段在HTML中生成 多選select 標籤 參數: attr 字典,指定生成標籤的屬性,如: attr = {'class': 'c1'} text_value_list 列表,用於指定select標籤中的option,如:[ {'value':1, 'text': '籃球'}, {'value':2, 'text': '足球'}, {'value':3, 'text': '乒乓球'}, {'value':4, 'text': '羽毛球'}, ] selected_value_list 列表,默認被選中選項對應的值,如:[2,3,4] """
八、動態初始化默認值
因爲Form能夠用於生成HTML標籤,若是想要在建立標籤的同時再爲其設置默認值有兩種方式:
class InitValueForm(Form):
username = StringField(error={'required': '用戶名不能爲空'})
age = IntegerField(max_value=500,
min_value=0,
error={'required': '年齡不能爲空',
'invalid': '年齡必須爲數字',
'min_value': '年齡不能小於0',
'max_value': '年齡不能大於500'})
city = IntegerField(error={'required': '年齡不能爲空', 'invalid': '年齡必須爲數字'},
widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '廣州'}])
)
gender = IntegerField(error={'required': '請選擇性別',
'invalid': '性別必須爲數字'},
widget=InputRadio(text_value_list=[{'value': 1, 'text': '男', },
{'value': 2, 'text': '女', }],
checked_value=2))
protocol = IntegerField(error={'required': '請選擇協議', 'invalid': '協議格式錯誤'},
widget=InputSingleCheckBox(attr={'value': 1}))
favor_int_val = IntegerListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '籃球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ]))
favor_str_val = StringListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '籃球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ]))
select_str_val = StringListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=MultiSelect(text_value_list=[{'value': '1', 'text': '籃球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ]))
select_int_val = IntegerListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '籃球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ]))
class InitValueHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
form = InitValueForm(self)
init_dict = {
'username': 'seven',
'age': 18,
'city': 2,
'gender': 2,
'protocol': 1,
'favor_int_val': [1, 3],
'favor_str_val': ['1', '3'],
'select_int_val': [1, 3],
'select_str_val': ['1', '3']
}
# 初始化操做,設置Form類中默認值以及默認選項
form.init_field_value(init_dict)
self.render('init_value.html', form=form)
九、更多示例
示例源碼下載:猛擊這裏
a. 基本使用
class RegisterForm(Form):
username = StringField(max_length=32,
min_length=6,
error={'required': '用戶名不能爲空',
'min_length': '用戶名不能少於6位',
'max_length': '用戶名不能超過32位'})
password = StringField(max_length=32,
min_length=6,
error={'required': '密碼不能爲空'},
widget=InputPassword())
gender = IntegerField(error={'required': '請選擇性別',
'invalid': '性別必須爲數字'},
widget=InputRadio(text_value_list=[{'value': 1, 'text': '男', },
{'value': 2, 'text': '女', }],
checked_value=2))
age = IntegerField(max_value=500,
min_value=0,
error={'required': '年齡不能爲空',
'invalid': '年齡必須爲數字',
'min_value': '年齡不能小於0',
'max_value': '年齡不能大於500'})
email = EmailField(error={'required': '郵箱不能爲空',
'invalid': '郵箱格式錯誤'})
city = IntegerField(error={'required': '城市選項不能爲空', 'invalid': '城市選項必須爲數字'},
widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '廣州'}])
)
protocol = IntegerField(error={'required': '請選擇協議', 'invalid': '協議格式錯誤'},
widget=InputSingleCheckBox(attr={'value': 1}))
memo = StringField(required=False,
max_length=150,
error={'invalid': '備註格式錯誤', 'max_length': '備註最大長度爲150字'},
widget=TextArea())
b. 多選checkbox
class MultiCheckBoxForm(Form):
favor_str_val = StringListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '籃球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ]))
favor_str_val_default = StringListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '籃球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ],
checked_value_list=['1', '4']))
favor_int_val = IntegerListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '籃球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ]))
favor_int_val_default = IntegerListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '籃球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ],
checked_value_list=[2, ]))
c、多選select
class MultiSelectForm(Form):
select_str_val = StringListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=MultiSelect(text_value_list=[{'value': '1', 'text': '籃球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ]))
select_str_val_default = StringListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=MultiSelect(text_value_list=[{'value': '1', 'text': '籃球', },
{'value': '2', 'text': '足球', },
{'value': '3', 'text': '乒乓球', },
{'value': '4', 'text': '羽毛球'}, ],
selected_value_list=['1', '3']))
select_int_val = IntegerListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '籃球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ]))
select_int_val_default = IntegerListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '籃球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ],
selected_value_list=[2]))
d. 動態select選項
class DynamicSelectForm(Form):
city = IntegerField(error={'required': '年齡不能爲空', 'invalid': '年齡必須爲數字'},
widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '廣州'}])
)
multi_favor = IntegerListField(error={'required': '請選擇愛好', 'invalid': '選擇愛好格式錯誤'},
widget=MultiSelect(text_value_list=[{'value': 1, 'text': '籃球', },
{'value': 2, 'text': '足球', },
{'value': 3, 'text': '乒乓球', },
{'value': 4, 'text': '羽毛球'}, ]))
def __init__(self, *args, **kwargs):
super(DynamicSelectForm, self).__init__(*args, **kwargs)
# 獲取數據庫中的最新數據並顯示在頁面上(每次建立對象都執行一次數據庫操做來獲取最新數據)
self.city.widget.text_value_list = [{'value': 1, 'text': '上海'},
{'value': 2, 'text': '北京'},
{'value': 3, 'text': '南京'},
{'value': 4, 'text': '廣州'}]
self.multi_favor.widget.text_value_list = [{'value': 1, 'text': '籃球'},
{'value': 2, 'text': '足球'},
{'value': 3, 'text': '乒乓球'},
{'value': 4, 'text': '羽毛球'},
{'value': 5, 'text': '玻璃球'}]
對Session來講Tornado是沒有的
簡單回顧下:
一、自動生成一段字符串
二、將字符串發送到客戶端的瀏覽器,同時把字符串當作key放在session裏。(能夠理解爲session就是一個字典)
三、在用戶的session對應的value裏設置任意值
操做session
request.session.set_expiry(value) * 若是value是個整數,session會在些秒數後失效。 * 若是value是個datatime或timedelta,session就會在這個時間後失效。 * 若是value是0,用戶關閉瀏覽器session就會失效。 * 若是value是None,session會依賴全局session失效策略。
二、上面是Django的原理是同樣的,那麼咱們來本身寫一個Session
2.一、儲備知識點
#!/usr/bin/env python # -*- coding:utf-8 -*- class Foo(object): def __getitem__(self, key): print '__getitem__',key def __setitem__(self, key, value): print '__setitem__',key,value def __delitem__(self, key): print '__delitem__',key
2.二、應用工廠方法模式定義session保存的位置,用戶只需在配置文件修改便可
class SessionHandler: def initialize(self): self.session_obj = SessionFacotory.get_session_obj(self) class SessionFacotory: @staticmethod def get_session_obj(handler): if conf.session_type == 'redis': return RedisSession(handler) elif conf.session_type == 'memcache': return RedisSession(handler) else: return MemorySession(handler)
2.3.緩存session
class CacheSession:
session_container = {}
session_id = "__sessionId__"
def __init__(self, handler):
self.handler = handler
client_random_str = 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 = create_session_id()
CacheSession.session_container[self.random_str] = {}
expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time)
def __getitem__(self, key):
ret = CacheSession.session_container[self.random_str].get(key, None)
return ret
def __setitem__(self, key, value):
CacheSession.session_container[self.random_str][key] = value
def __delitem__(self, key):
if key in CacheSession.session_container[self.random_str]:
del CacheSession.session_container[self.random_str][key]
2.4. memcache session
import memcache
conn = memcache.Client(['192.168.11.119:12000'], debug=True, cache_cas=True)
class MemcachedSession:
session_id = "__sessionId__"
def __init__(self, handler):
self.handler = handler
# 從客戶端獲取隨機字符串
client_random_str = handler.get_cookie(CacheSession.session_id, None)
# 若是從客戶端獲取到了隨機字符串
#
if client_random_str and conn.get(client_random_str):
self.random_str = client_random_str
else:
self.random_str = create_session_id()
conn.set(self.random_str, json.dumps({}), config.SESSION_EXPIRES)
#CacheSession.session_container[self.random_str] = {}
conn.set(self.random_str, conn.get(self.random_str), config.SESSION_EXPIRES)
expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(MemcachedSession.session_id, self.random_str, expires=expires_time)
def __getitem__(self, key):
# ret = CacheSession.session_container[self.random_str].get(key, None)
ret = conn.get(self.random_str)
ret_dict = json.loads(ret)
result = ret_dict.get(key,None)
return result
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)
# CacheSession.session_container[self.random_str][key] = value
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)
2.5 redis session
import redis
pool = redis.ConnectionPool(host='192.168.11.119', port=6379)
r = redis.Redis(connection_pool=pool)
class RedisSession:
session_id = "__sessionId__"
def __init__(self, handler):
self.handler = handler
# 從客戶端獲取隨機字符串
client_random_str = handler.get_cookie(CacheSession.session_id, None)
# 若是從客戶端獲取到了隨機字符串
if client_random_str and r.exists(client_random_str):
self.random_str = client_random_str
else:
self.random_str = create_session_id()
r.hset(self.random_str,None,None)
# conn.set(self.random_str, json.dumps({}), config.SESSION_EXPIRES)
# CacheSession.session_container[self.random_str] = {}
r.expire(self.random_str, config.SESSION_EXPIRES)
# conn.set(self.random_str, conn.get(self.random_str), config.SESSION_EXPIRES)
expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(RedisSession.session_id, self.random_str, expires=expires_time)
def __getitem__(self, key):
# ret = CacheSession.session_container[self.random_str].get(key, None)
result = r.hget(self.random_str,key)
if result:
ret_str = str(result, encoding='utf-8')
try:
result = json.loads(ret_str)
except:
result = ret_str
return result
else:
return result
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)
# CacheSession.session_container[self.random_str][key] = value
def __delitem__(self, key):
r.hdel(self.random_str,key)
Cookie,有時也用其複數形式Cookies,指某些網站爲了辨別用戶身份、進行session跟蹤而儲存在用戶本地終端上的數據(一般通過加密)。定義於RFC2109和2965都已廢棄,最新取代的規範是RFC6265。(能夠叫作瀏覽器緩存)
一、cookie的基本操做
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): print(self.cookies) # 獲取全部的cookie self.set_cookie('k1','v1') # 設置cookie print(self.get_cookie('k1')) # 獲取指定的cookie self.write("Hello, world") application = tornado.web.Application([ (r"/index", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
二、加密cookie(簽名)
Cookie 很容易被惡意的客戶端僞造。加入你想在 cookie 中保存當前登錄用戶的 id 之類的信息,你須要對 cookie 做簽名以防止僞造。Tornado 經過 set_secure_cookie 和 get_secure_cookie 方法直接支持了這種功能。 要使用這些方法,你須要在建立應用時提供一個密鑰,名字爲 cookie_secret。 你能夠把它做爲一個關鍵詞參數傳入應用的設置中:
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): if not self.get_secure_cookie("mycookie"): # 獲取帶簽名的cookie self.set_secure_cookie("mycookie", "myvalue") # 設置帶簽名的cookie self.write("Your cookie was not set yet!") else: self.write("Your cookie was set!") application = tornado.web.Application([ (r"/index", MainHandler), ]) if __name__ == "__main__": application.listen(8888) tornado.ioloop.IOLoop.instance().start()
簽名Cookie的本質是:
寫cookie過程: 將值進行base64加密 對除值之外的內容進行簽名,哈希算法(沒法逆向解析) 拼接 簽名 + 加密值 讀cookie過程: 讀取 簽名 + 加密值 對簽名進行驗證 base64解密,獲取值內容
3.JavaScript操做Cookie
/* 設置cookie,指定秒數過時, name表示傳入的key, value表示傳入相對應的value值, expires表示當前日期在加5秒過時 */ function setCookie(name,value,expires){ var temp = []; var current_date = new Date(); current_date.setSeconds(current_date.getSeconds() + 5); document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString(); }
上傳文件這塊能夠分爲兩大類,第一類是經過form表單驗證進行上傳,還有一類就是經過ajax上傳,下面就來介紹一下這兩類
一、form表單上傳文件
import tornado.web
import tornado.ioloop
import os
class IndexHandler(tornado.web.RequestHandler):
def get(self, *args, **kwargs):
self.render('index.html')
def post(self, *args, **kwargs):
file_metas = self.request.files["filename"] # 獲取文件信息
for meta in file_metas:
file_name = meta['filename'] # 得到他的文件名字
file_names = os.path.join('static','img',file_name)
with open(file_names,'wb') as up: # 打開本地一個文件
up.write(meta['body']) # body就是文件內容,把他寫到本地
settings = {
'template_path':'views',
'static_path':'static',
'static_url_prefix': '/statics/',
}
application = tornado.web.Application([
(r'/index',IndexHandler)
],**settings)
if __name__ == '__main__':
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>上傳文件</title> </head> <body> <form action="/index" method="post" enctype="multipart/form-data"> <input type="file" name = "filename"> <input type="submit" value="提交"> </form> </body> </html>
二、ajax上傳文件
「假裝ajax」 iframe上傳
<iframe id="my_iframe" name="my_iframe" style="display: none" src=""></iframe> <form id="fo" method="POST" action="/upload/" enctype="multipart/form-data"> <input type="text" id="user" name="user" /> <input type="file" id="img" name="img" onchange="uploadFile3();" /> <input type="submit" /> </form> ##Js function uploadFile3(){ $('#container').find('img').remove(); document.getElementById('my_iframe').onload = callback; document.getElementById('fo').target = 'my_iframe'; document.getElementById('fo').submit(); } function callback(){ var text = $('#my_iframe').contents().find('body').text(); var json_data = JSON.parse(text); console.log(json_data); if(json_data.status){ // 已經上傳成功 // 預覽,建立image標籤,src指向剛上傳的靜態文件路徑 var tag = document.createElement('img'); tag.src = "/" + json_data.data; tag.className = 'img'; $('#container').append(tag); }else{ alert(json_data.error); } }
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="file" id="img" /> <input type="button" onclick="UploadFile();" value="提交"/> <script src="/statics/jquery-1.12.4.js"></script> <script> function UploadFile(){ var fileObj = $("#img")[0].files[0]; var form = new FormData(); form.append("filename", fileObj); $.ajax({ type:'POST', url: '/index', data: form, processData: false, // tell jQuery not to process the data contentType: false, // tell jQuery not to set contentType success: function(arg){ console.log(arg); } }) } </script> </body> </html>
<input type="file" id="img" name="img" onchange="uploadFile3();" /> <a onclick="uploadFile1();" >XMLHttpRequet上傳</a> function uploadFile1(){ // 建立表單對象 var form = new FormData(); // 在表單對象中添加:user: 用戶輸入的用戶名 form.append('user',document.getElementById('user').value); // 在表單對象中添加:img: 文件對象 var fileObj = document.getElementById("img").files[0]; form.append("img", fileObj); var xhr = new XMLHttpRequest(); // 回調函數,當Ajax請求狀態變化時,自動觸發 xhr.onreadystatechange = function(){ // xhr.readyState=4 表示,客戶端已經將服務器端響應的內容所有獲取完畢 if(xhr.readyState == 4){ // xhr.responseText 獲取服務器端響應的文本內容,即: views中 return HttpResponse中的內容 var data = xhr.responseText; console.log(data); } }; // 建立異步鏈接 xhr.open("post", '/upload/', true); // 發送請求,將form中的數據發送到服務器端 xhr.send(form); }
用python生成隨機驗證碼須要借鑑一個插件,和一個io模塊,實現起來也很是容易,固然也須要借鑑session來判斷驗證碼是否錯誤,下面寫一段用戶登陸驗證帶驗證碼的,再看下效果,插件必須和執行文件必須放在更目錄下
import io
import datetime
import json
from backend.utils import check_code
from forms import account
from backend.utils.response import BaseResponse
from backend import commons
from models import chouti_orm as ORM
from sqlalchemy import and_, or_
create_session_id = lambda: sha1(bytes('%s%s' % (os.urandom(16), time.time()), encoding='utf-8')).hexdigest()
class SessionFactory:
@staticmethod
def get_session_obj(handler):
obj = None
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
class CacheSession:
session_container = {}
session_id = "__sessionId__"
def __init__(self, handler):
self.handler = handler
client_random_str = 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 = create_session_id()
CacheSession.session_container[self.random_str] = {}
expires_time = time.time() + config.SESSION_EXPIRES
handler.set_cookie(CacheSession.session_id, self.random_str, expires=expires_time)
def __getitem__(self, key):
ret = CacheSession.session_container[self.random_str].get(key, None)
return ret
def __setitem__(self, key, value):
CacheSession.session_container[self.random_str][key] = value
def __delitem__(self, key):
if key in CacheSession.session_container[self.random_str]:
del CacheSession.session_container[self.random_str][key]
class BaseRequestHandler(tornado.web.RequestHandler):
def initialize(self):
self.session = SessionFactory.get_session_obj(self)
class CheckCodeHandler(BaseRequestHandler):
def get(self, *args, **kwargs):
stream = io.BytesIO()
img, code = check_code.create_validate_code()
img.save(stream, "png")
self.session["CheckCode"] = code
self.write(stream.getvalue())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>驗證碼</title> </head> <body> <form action="/login" method="post"> <p>用戶名: <input type="text" name="username"> </p> <p>密碼: <input type="password" name="password"> </p> <p>驗證碼: <input type="text" name="code"><img src="/check_code" onclick="ChangeCode();" id = "checkcode"></p> <input type="submit" value="submit"> <span>{{state}}</span> </form> <script type="text/javascript"> //當點擊圖片的時候,會刷新圖片,這一段代碼就能夠實現 function ChangeCode() { var code = document.getElementById('checkcode'); code.src += "?"; } </script> </body> </html>
插件下載地址:猛擊這裏