一 Django自定义分页
目的:自定义分页功能,并把它写成模块(注意其中涉及到的python基础知识)
models.py文件
# Create your models here.
class UserList(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
分页模块page.py文件
#!/usr/bin/env python
#-*- coding:utf-8 -*-
__author__ = 'mcp'
# 导入后台标记字符串安全的模块
from django.utils.safestring import mark_safe
# 自定义的分页类
class Pager(object):
def __init__(self, current_page):
self.current_page = int(current_page)
# 让方法伪装成属性,加装饰器
@property
def start(self):
return (self.current_page-1)*10
@property
def end(self):
return self.current_page*10
def page_str(self,all_item,base_url):
all_page,div = divmod(all_item,10)
if div>0:
all_page += 1
pager_list = []
if all_page <= 11:
start = 1
end = all_page
else:
if self.current_page < 6:
start = 1
end =11 + 1
else:
start = self.current_page - 5
end = self.current_page + 6
if self.current_page + 6 > all_page:
start = all_page - 11
end = all_page + 1
for i in range(start,end):
# 注意单双引号的使用,/user_list/?page=
if i == self.current_page:
tmp = '%d' %(base_url,i,i,)
else:
tmp = '%d' %(base_url,i,i,)
pager_list.append(tmp)
# 上一页
if self.current_page > 1:
pre_page = '上一页' %(base_url,self.current_page - 1)
else:
pre_page = '上一页'
# 下一页
if self.current_page < all_page:
next_page = '下一页' %(base_url,self.current_page + 1)
else:
next_page = '下一页'
#在最前面插入上一页按钮
pager_list.insert(0,pre_page)
#在最后面插入下一页按钮
pager_list.append(next_page)
# return ''.join(pager_list)
# 直接在后台标记字符串是安全的
return mark_safe(''.join(pager_list))
views.py文件
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models
# 导入自定义分页模块
from app01 import page
# Create your views here.
def user_list(request):
# 先创建100条表数据
# for item in range(101,500):
# dic = {'username':'name%d' %item, 'age':item}
# models.UserList.objects.create(**dic)
# 再打印数据库中有多少条数据
# print models.UserList.objects.all().count()
# 获取第0-9条数据,分片
# print type(models.UserList.objects.all()) #
# result = models.UserList.objects.all()[0:10]
current_page = request.GET.get('page',1)
# 注意current_page为字符串类型,要转换成整型
# current_page = int(current_page)
# start = (current_page-1)*10
# end = current_page*10
# result = models.UserList.objects.all()[start:end]
pager_obj = page.Pager(current_page)
# result = models.UserList.objects.all()[pager_obj.start():pager_obj.end()]
# 下面这句是从Django ORM中取数据,相当于在数据库中执行如下sql语句
# SELECT "app01_userlist"."id", "app01_userlist"."username", "app01_userlist"."age"
# FROM "app01_userlist" LIMIT 10 OFFSET 490
result = models.UserList.objects.all()[pager_obj.start:pager_obj.end]
# 打印Django ORM中在底层实际执行的sql语句
print result.query
# 每页显示10条数据
# 共100条
all_item = models.UserList.objects.all().count()
# 把下面的代码封装到函数中了
pager_str = pager_obj.page_str(all_item,"/user_list/?page=")
# all_page,div = divmod(all_item,10)
# if div>0:
# all_page += 1
#
# pager_str = ""
# for i in range(1,all_page+1):
# # 注意单双引号的使用
# tmp = '%d' %(i,i,)
# pager_str += tmp
return render(request,'user_list.html',{'result':result,'pager_str':pager_str})
user_list.html文件
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<style>
a{
padding: 5px;
}
style>
head>
<body>
<h1>测试h1>
<table>
<tbody>
{% for line in result %}
<tr>
<td>{{ line.username }}td>
<td>{{ line.age }}td>
tr>
{% endfor %}
tbody>
table>
{# <div>#}
{# <a href="/user_list/?page=1">1a>#}
{# <a href="/user_list/?page=2">2a>#}
{# <a href="/user_list/?page=3">3a>#}
{# <a href="/user_list/?page=4">4a>#}
{# <a>5a>#}
{# <a>6a>#}
{# <a>7a>#}
{# <a>8a>#}
{# <a>9a>#}
{# <a>10a>#}
{# div>#}
<div>
{#在前端标记后台传的字符串是安全的#}
{#{{ pager_str | safe }}#}
{{ pager_str }}
div>
body>
html>
自定义分页模块涉及到的知识以及注意点:
(1)Django ORM
(2)python中类、属性、div方法以及封装特性
(3)XSS攻击(在前端或后端标记字符串是安全的)
(4)python相关基础知识以及装饰器
二 自定义Tornado的Session框架
1 知识回顾
Tornado中没有Session部分,这需要开发者去自己扩展Tornado的Session框架。在自定义Session框架之前,先来回顾下Django中Session和Cookie的知识:
用户登录过程中的Session和Cookie:
1、在服务端随机生成一串字符;
2、将该字符串写到浏览器端,同时将该字符串存储在服务端,存储形式为字典,其中该字符串为key(服务端Session为字典形式);
3、在服务端Session中设置相应值,比如是否已经登录。
操作Session: |
2 自定义Session
(1)知识储备
#!/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
# 创建obj对象
obj = Foo()
# 获取key为'k1'的元素,这时会调用__getitem__方法
result = obj['k1']
# 给key为'k2'的元素赋值,这时会调用__setitem__方法
#obj['k2'] = 'wupeiqi'
# 删除key为'k3'的元素,这时会调用__delitem__方法
#del obj['k3']
(2)Session框架代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
from hashlib import sha1
import os, time
session_container = {}
create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()
class Session(object):
session_id = "__sessionId__"
def __init__(self, request):
#当请求过来时,先利用get_cookie方法获取cookie值,目的是为了确定是否存在Cookie,如果有则不生成,否则生成。
session_value = request.get_cookie(Session.session_id)
#如果Cookie不存在,则生成Cookie(创建随机字符串)
if not session_value:
self._id = create_session_id()
else:
#如果Cookie存在,则直接将获取的Cookie值赋值给_id字段
self._id = session_value
#设置Session值
request.set_cookie(Session.session_id, self._id)
#特殊方法:获取值时调用的方法
def __getitem__(self, key):
ret = None
try:
#获取Session值方法
ret = session_container[self._id][key]
except Exception,e:
pass
return ret
#特殊方法:设置值时调用的方法
def __setitem__(self, key, value):
#判断是否存在Cookie值,如果存在设置相应的值
if session_container.has_key(self._id):
session_container[self._id][key] = value
#如果不存在,则生成相应的字典数据,类似:{'Cookie值':{'IS_LOGIN':'True'}}
else:
session_container[self._id] = {key: value}
#特殊方法:删除值时调用的方法
def __delitem__(self, key):
del session_container[self._id][key]
class BaseHandler(tornado.web.RequestHandler):
#扩展了Tornado的initialize方法,这个方法默认为空方法
def initialize(self):
'''
这里initialize的self指向谁?
obj = LoginHandler()
obj.initialize() ==>LoginHandler类中没有initialize这个方法,该方法继承自它的父类
所以initialize的self就是LoginHandler对象
'''
#执行Session类的构造方法,同时把LoginHandler对象传参给Session类的构造方法
self.my_session = Session(self)
class MainHandler(BaseHandler):
def get(self):
ret = self.my_session['is_login']
if ret:
self.write('index')
else:
self.redirect("/login")
class LoginHandler(BaseHandler):
def get(self):
'''
当用户浏览器访问服务端时,就应该给浏览器写入cookie了,但是这里没有写?
那在哪里写入cookie呢?上面定义的相关Handler类都是继承自RequestHandler,这次继承的是自定义的BaseHandler类,
继承自定义的类,然后在类中扩展了initialize方法,获取用户cookie或者写cookie都可以在此方法中操作
'''
# self.set_cookie()
# self.get_cookie()
self.render('login.html', **{'status': ''})
def post(self, *args, **kwargs):
#获取用户提交的用户名和密码
username = self.get_argument('username')
password = self.get_argument('pwd')
if username == 'wupeiqi' and password == '123':
#如果认证通过,就可以访问这个self.my_session对象,然后就可以把Cookie写入字典中。
self.my_session['is_login'] = 'true'
self.redirect('/index')
else:
self.render('login.html', **{'status': '用户名或密码错误'})
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': '/static/',
'cookie_secret': 'abcdefgh',
'login_url': '/login'
}
application = tornado.web.Application([
#创建两个URL 分别对应MainHandler和LoginHandler
(r"/index", MainHandler),
(r"/login", LoginHandler),
], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
(3)分布式Session框架
上面使用Tornado预留扩展方法initialize和Class类实现了自定义的Session框架,下面探讨如何实现分布式Session框架。上面自定义的Session框架中,Session默认保存在session_container字典中。实际生产环境中,Session也可以存储在Redis,memcache,mysql中,如果把session存储在单台服务器上,那么存在着数据不安全或数据量大时满足不了性能要求。这时可以考虑分布式(假设有3台服务器存储Session),那么可以分别存储在A、B、C上:
当用户第1次访问时,通过权重和hash计算把session加入到hash环中,实现分布式存储;当用户第2次携带Cookie访问时,通过计算找到相应的Session值并进行认证。
一致性哈希
#!/usr/bin/env python
#coding:utf-8
import sys
import math
from bisect import bisect
if sys.version_info >= (2, 5):
import hashlib
md5_constructor = hashlib.md5
else:
import md5
md5_constructor = md5.new
class HashRing(object):
#一致性哈希
def __init__(self,nodes):
'''
初始化: 包含存储节点以及节点对应的权重
默认每1个节点有32个虚拟节点
对于权重,通过多创建虚拟节点来实现
如:nodes = [
{'host':'127.0.0.1:8000','weight':1},
{'host':'127.0.0.1:8001','weight':2},
{'host':'127.0.0.1:8002','weight':1},
]
'''
self.ring = dict()
self._sorted_keys = []
self.total_weight = 0
self.__generate_circle(nodes)
def __generate_circle(self,nodes):
for node_info in nodes:
self.total_weight += node_info.get('weight',1)
for node_info in nodes:
weight = node_info.get('weight',1)
node = node_info.get('host',None)
virtual_node_count = math.floor((32*len(nodes)*weight) / self.total_weight)
for i in xrange(0,int(virtual_node_count)):
key = self.gen_key_thirty_two( '%s-%s' % (node, i) )
if self._sorted_keys.__contains__(key):
raise Exception('该节点已经存在.')
self.ring[key] = node
self._sorted_keys.append(key)
def add_node(self,node):
'''
新建节点node: 新添加节点格式为:{'host':'127.0.0.1:8002','weight':1},其中第1个元素表示节点,
第2个元素表示该节点的权重。
'''
node = node.get('host',None)
if not node:
raise Exception('节点的地址不能为空.')
weight = node.get('weight',1)
self.total_weight += weight
nodes_count = len(self._sorted_keys) + 1
virtual_node_count = math.floor((32 * nodes_count * weight) / self.total_weight)
for i in xrange(0,int(virtual_node_count)):
key = self.gen_key_thirty_two( '%s-%s' % (node, i) )
if self._sorted_keys.__contains__(key):
raise Exception('该节点已经存在.')
self.ring[key] = node
self._sorted_keys.append(key)
def remove_node(self,node):
'''
移除节点node: 要移除的节点'127.0.0.1:8000'
'''
for key,value in self.ring.items():
if value == node:
del self.ring[key]
self._sorted_keys.remove(key)
def get_node(self,string_key):
'''
获取string_key所在的节点
'''
pos = self.get_node_pos(string_key)
if pos is None:
return None
return self.ring[ self._sorted_keys[pos]].split(':')
def get_node_pos(self,string_key):
'''
获取string_key所在的节点的索引
'''
if not self.ring:
return None
key = self.gen_key_thirty_two(string_key)
nodes = self._sorted_keys
pos = bisect(nodes, key)
return pos
def gen_key_thirty_two(self, key):
m = md5_constructor()
m.update(key)
return long(m.hexdigest(), 16)
def gen_key_sixteen(self,key):
b_key = self.__hash_digest(key)
return self.__hash_val(b_key, lambda x: x)
def __hash_val(self, b_key, entry_fn):
return (( b_key[entry_fn(3)] << 24)|(b_key[entry_fn(2)] << 16)|(b_key[entry_fn(1)] << 8)| b_key[entry_fn(0)] )
def __hash_digest(self, key):
m = md5_constructor()
m.update(key)
return map(ord, m.digest())
"""
nodes = [
{'host':'127.0.0.1:8000','weight':1},
{'host':'127.0.0.1:8001','weight':2},
{'host':'127.0.0.1:8002','weight':1},
]
ring = HashRing(nodes)
result = ring.get_node('98708798709870987098709879087')
print result
"""
分布式Session框架代码:
from hashlib import sha1
import os, time
create_session_id = lambda: sha1('%s%s' % (os.urandom(16), time.time())).hexdigest()
class Session(object):
session_id = "__sessionId__"
def __init__(self, request):
session_value = request.get_cookie(Session.session_id)
if not session_value:
self._id = create_session_id()
else:
self._id = session_value
request.set_cookie(Session.session_id, self._id)
def __getitem__(self, key):
# 根据 self._id ,在一致性哈西中找到其对应的服务器IP
# 找到相对应的redis服务器,如: r = redis.StrictRedis(host='localhost', port=6379, db=0)
# 使用python redis api 链接
# 获取数据,即:
# return self._redis.hget(self._id, name)
def __setitem__(self, key, value):
# 根据 self._id ,在一致性哈西中找到其对应的服务器IP
# 使用python redis api 链接
# 设置session
# self._redis.hset(self._id, name, value)
def __delitem__(self, key):
# 根据 self._id 找到相对应的redis服务器
# 使用python redis api 链接
# 删除,即:
return self._redis.hdel(self._id, name)
三 自定义Tornado的Form框架
python web框架中,只有Django提供了form框架。在Tornado等其他python web框架中,需要自定义form框架。Django中的form验证流程:
用户输入 ==》request.post ==> obj = Form(request.POST) ==> obj.is_valid()
存在问题:request在获取用户输入时并不知道用户输入的个数,Form表单内可能有1个也有可能有多个输入,这是Django中Form框架存在的问题。
Form(模型绑定)有两个主要功能:
(1)自动生成html表单
(2)用户输入验证
1 简单的form框架
index.html文件
DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>title>
<link href="{{static_url("commons.css")}}" rel="stylesheet" />
head>
<body>
<h1>helloh1>
<form action="/index" method="post">
<p>hostname: <input type="text" name="host" /> p>
<p>ip: <input type="text" name="ip" /> p>
<p>port: <input type="text" name="port" /> p>
<p>phone: <input type="text" name="phone" /> p>
<input type="submit" />
form>
body>
html>
index.py文件
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
from hashlib import sha1
import os, time
import re
#创建form类
class MainForm(object):
#初始化
def __init__(self):
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):
#循环当前类中的成员,注意此种方法
for key, regular in self.__dict__.items():
'''
通过request.get_argument()来获取用户前端输入的值
在循环时,不需要关心前端输入值的个数,这里以自定义方法为主
'''
post_value = request.get_argument(key)
#前端提交的数据与自定义的正则表达式进行匹配验证
ret = re.match(regular, post_value)
print key, ret, post_value
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
def post(self, *args, **kwargs):
obj = MainForm()
result = obj.check_valid(self)
self.write('ok')
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': '/static/',
'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
'login_url': '/login'
}
application = tornado.web.Application([
(r"/index", MainHandler),
], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
2 自定义form框架优化版
(1)验证字段写成相应的类;
(2)类的继承
(3)ListForm
自定义Form完整代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import tornado.ioloop
import tornado.web
import re
class Field(object):
def __init__(self, error_msg_dict, required):
self.id_valid = False
self.value = None
self.error = None
self.name = None
self.error_msg = error_msg_dict
self.required = required
def match(self, name, value):
self.name = name
if not self.required:
self.id_valid = True
self.value = value
else:
if not value:
if self.error_msg.get('required', None):
self.error = self.error_msg['required']
else:
self.error = "%s is required" % name
else:
ret = re.match(self.REGULAR, value)
if ret:
self.id_valid = True
self.value = ret.group()
else:
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
else:
self.error = "%s is invalid" % name
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}$"
def __init__(self, error_msg_dict=None, required=True):
error_msg = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(IPField, self).__init__(error_msg_dict=error_msg, required=required)
class IntegerField(Field):
REGULAR = "^\d+$"
def __init__(self, error_msg_dict=None, required=True):
error_msg = {'required': '数字不能为空', 'valid': '数字格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(IntegerField, self).__init__(error_msg_dict=error_msg, required=required)
class CheckBoxField(Field):
def __init__(self, error_msg_dict=None, required=True):
error_msg = {} # {'required': 'IP不能为空', 'valid': 'IP格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(CheckBoxField, self).__init__(error_msg_dict=error_msg, required=required)
def match(self, name, value):
self.name = name
if not self.required:
self.id_valid = True
self.value = value
else:
if not value:
if self.error_msg.get('required', None):
self.error = self.error_msg['required']
else:
self.error = "%s is required" % name
else:
if isinstance(name, list):
self.id_valid = True
self.value = value
else:
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
else:
self.error = "%s is invalid" % name
class FileField(Field):
REGULAR = "^(\w+\.pdf)|(\w+\.mp3)|(\w+\.py)$"
def __init__(self, error_msg_dict=None, required=True):
error_msg = {} # {'required': '数字不能为空', 'valid': '数字格式错误'}
if error_msg_dict:
error_msg.update(error_msg_dict)
super(FileField, self).__init__(error_msg_dict=error_msg, required=required)
def match(self, name, value):
self.name = name
self.value = []
if not self.required:
self.id_valid = True
self.value = value
else:
if not value:
if self.error_msg.get('required', None):
self.error = self.error_msg['required']
else:
self.error = "%s is required" % name
else:
m = re.compile(self.REGULAR)
if isinstance(value, list):
for file_name in value:
r = m.match(file_name)
if r:
self.value.append(r.group())
self.id_valid = True
else:
self.id_valid = False
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
else:
self.error = "%s is invalid" % name
break
else:
if self.error_msg.get('valid', None):
self.error = self.error_msg['valid']
else:
self.error = "%s is invalid" % name
def save(self, request, upload_path=""):
file_metas = request.files[self.name]
for meta in file_metas:
file_name = meta['filename']
with open(file_name,'wb') as up:
up.write(meta['body'])
class Form(object):
def __init__(self):
self.value_dict = {}
self.error_dict = {}
self.valid_status = True
def validate(self, request, depth=10, pre_key=""):
self.initialize()
self.__valid(self, request, depth, pre_key)
def initialize(self):
pass
def __valid(self, form_obj, request, depth, pre_key):
"""
验证用户表单请求的数据
:param form_obj: Form对象(Form派生类的对象)
:param request: Http请求上下文(用于从请求中获取用户提交的值)
:param depth: 对Form内容的深度的支持
:param pre_key: Html中name属性值的前缀(多层Form时,内部递归时设置,无需理会)
:return: 是否验证通过,True:验证成功;False:验证失败
"""
depth -= 1
if depth < 0:
return None
form_field_dict = form_obj.__dict__
for key, field_obj in form_field_dict.items():
print key,field_obj
if isinstance(field_obj, Form) or isinstance(field_obj, Field):
if isinstance(field_obj, Form):
# 获取以key开头的所有的值,以参数的形式传至
self.__valid(field_obj, request, depth, key)
continue
if pre_key:
key = "%s.%s" % (pre_key, key)
if isinstance(field_obj, CheckBoxField):
post_value = request.get_arguments(key, None)
elif isinstance(field_obj, FileField):
post_value = []
file_list = request.request.files.get(key, None)
for file_item in file_list:
post_value.append(file_item['filename'])
else:
post_value = request.get_argument(key, None)
print post_value
# 让提交的数据 和 定义的正则表达式进行匹配
field_obj.match(key, post_value)
if field_obj.id_valid:
self.value_dict[key] = field_obj.value
else:
self.error_dict[key] = field_obj.error
self.valid_status = False
class ListForm(object):
def __init__(self, form_type):
self.form_type = form_type
self.valid_status = True
self.value_dict = {}
self.error_dict = {}
def validate(self, request):
name_list = request.request.arguments.keys() + request.request.files.keys()
index = 0
flag = False
while True:
pre_key = "[%d]" % index
for name in name_list:
if name.startswith(pre_key):
flag = True
break
if flag:
form_obj = self.form_type()
form_obj.validate(request, depth=10, pre_key="[%d]" % index)
if form_obj.valid_status:
self.value_dict[index] = form_obj.value_dict
else:
self.error_dict[index] = form_obj.error_dict
self.valid_status = False
else:
break
index += 1
flag = False
class MainForm(Form):
def __init__(self):
# self.ip = IPField(required=True)
# self.port = IntegerField(required=True)
# self.new_ip = IPField(required=True)
# self.second = SecondForm()
self.fff = FileField(required=True)
super(MainForm, self).__init__()
#
# class SecondForm(Form):
#
# def __init__(self):
# self.ip = IPField(required=True)
# self.new_ip = IPField(required=True)
#
# super(SecondForm, self).__init__()
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.render('index.html')
def post(self, *args, **kwargs):
# for i in dir(self.request):
# print i
# print self.request.arguments
# print self.request.files
# print self.request.query
# name_list = self.request.arguments.keys() + self.request.files.keys()
# print name_list
# list_form = ListForm(MainForm)
# list_form.validate(self)
#
# print list_form.valid_status
# print list_form.value_dict
# print list_form.error_dict
# obj = MainForm()
# obj.validate(self)
#
# print "验证结果:", obj.valid_status
# print "符合验证结果:", obj.value_dict
# print "错误信息:"
# for key, item in obj.error_dict.items():
# print key,item
# print self.get_arguments('favor'),type(self.get_arguments('favor'))
# print self.get_argument('favor'),type(self.get_argument('favor'))
# print type(self.get_argument('fff')),self.get_argument('fff')
# print self.request.files
# obj = MainForm()
# obj.validate(self)
# print obj.valid_status
# print obj.value_dict
# print obj.error_dict
# print self.request,type(self.request)
# obj.fff.save(self.request)
# from tornado.httputil import HTTPServerRequest
# name_list = self.request.arguments.keys() + self.request.files.keys()
# print name_list
# print self.request.files,type(self.request.files)
# print len(self.request.files.get('fff'))
# obj = MainForm()
# obj.validate(self)
# print obj.valid_status
# print obj.value_dict
# print obj.error_dict
# obj.fff.save(self.request)
self.write('ok')
settings = {
'template_path': 'template',
'static_path': 'static',
'static_url_prefix': '/static/',
'cookie_secret': 'aiuasdhflashjdfoiuashdfiuh',
'login_url': '/login'
}
application = tornado.web.Application([
(r"/index", MainHandler),
], **settings)
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
参考资料:
http://www.cnblogs.com/wupeiqi/articles/5341480.html
http://www.cnblogs.com/luotianshuai/p/5482612.html