PythonTip >> 博文 >> python

pyramid构建的一个项目的架子

zihua 2014-01-20 23:01:48 点击: 874 | 收藏


最近立项一个项目,项目基本需求如下: 

SaaS能力 

SNS 

移动应用 

高效率 

高可定制 

高扩展能力 

Nosql 

快速开发 

快速迭代 

经过一个月的摸索,选定python作为主项目语言,并在诸多框架中选定pyramid 

,理由就不多说了。各种模块选定也花了很长时间,如果大家不熟悉pyramid,又想用pyramid做项目,可以作为参考,能节省点时间,同时希望有pyra mid开发经验的老大们给指导下。 

项目的基本目录结构如下(仅是例举): 

static (静态内容) 

---img 

---baseimg(系统内定的图片) 

---userimg(用户上传的) 

---css 

---bootstrap.css 

---jquerymobile.css 

---main.css 

… 

---js 

---jquery  (.. ui … tools…mobile) 

---backbone( undercore .. mustache 前端mvc) 

---custom 

templete(mako模板) 

---user 

---index.mako 

---userinfo.mako(widget,页面中的某一部分) 

---login.mako 

---reg.mako 

…(widget or page) 

---blog 

---content.mako 

---bloglist.mako 

… 

---orther modules ….. 

---index.mako (首页面模板) 

---base.mako(页面母版,定义页面轮廓,接受其它mako页的inherited) 

app 

---user                     --->这样归类代码的好处就是---干净! 

---usertraversalmodel.py (traversal风格url处理) 

---userview.py(controller) 

---userwidget.py(child controller) 

... 

---blog 

…. 

---other app modules….. 

mobile 

---user 

---blog 

---other mobile page 

test 

(未实现) 

---__init__.py 

---resource.py (主Root traversal class) 

---beaker_mongo.py(mongodb beaker插件,用于sessions) 

---baseroot.py(traversal root class基类,用于各模块类继承) 

---views.py (基本显示页面,主页,错误页等) 

搭建起来的框架的基本能力包括: 

1.  集成pymongo 

压入request中,将来在任意模块中通过request.db….访问数据库 

(虽然看起来很别扭,但很实用),init中: 

def add_mongo_db(event): 

settings = event.request.registry.settings 

url = settings['mongodb.url'] 

db_name = settings['mongodb.db_name'] 

db = settings['mongodb_conn'][db_name] 

event.request.db = db 

event.request.askdata={} 

db_uri = settings['mongodb.url'] 

conn = pymongo.Connection(db_uri) 

config.registry.settings['mongodb_conn'] = conn 

config.add_subscriber(add_mongo_db, NewRequest) 

2.  采用beaker+mongodb处理session,init中: 

from mongodb_beaker  import MongoDBNamespaceManager 

from pyramid_beaker import session_factory_from_settings 

session_factory = session_factory_from_settings(settings) 

authn_policy = AuthTktAuthenticationPolicy(settings['secret_key']) 

authz_policy = ACLAuthorizationPolicy() 

config = Configurator(settings=settings, 

authentication_policy = authn_policy, 

authorization_policy = authz_policy, 

session_factory=session_factory, 

root_factory=Root) 

3.  实现traversal ,由于不熟悉这东东,搞了n多天,比较烦一堆route定义或正则,麻烦,所以用这个 

由于python不能相互import,所以: 

baseroot -->Root 

baseroot-->otherclass 

Baseroot.py 

#coding:utf8 

class BaseRoot1(dict,object): 

def __init__(self,request,name=None,parent=None): 

self.request = request 

self.__name__ = name 

self.__parent__ = parent 

self.children = {} 

def add_child(self,name,klass=None,**kw): 

if klass is None: 

child = BaseRoot1(name,self.request,self) 

else: 

child = klass(name,self.request,self, **kw) 

#print 'sdf' 

self.children[name] = child 

def __getitem__(self,name): 

pass 

resource.py 

from baseroot  import  BaseRoot1 

class Root(BaseRoot1): 

"""根资源""" 

def __init__(self,request,name=None,parent=None): 

"""根资源的创建函数""" 

self.request = request 

self.__name__ = name 

self.__parent__ = parent 

self.children = {} 

def add_child(self,name,klass=None,**kw): 

if klass is None: 

child = Root(name,self.request,self) 

else: 

child = klass(name,self.request,self, **kw) 

self.children[name] = child 

def __getitem__(self,name): 

if name=='user': 

return User(self.request,'user',self) 

#开始traval,使用traversal的好处就是可以在这里加处理代码 这里name就是url中的某个节 

elif name=='blog': 

return Blog(self.request,'blog',self) 

elif name<>'': 

return self.children[name] 

else: 

raise KeyError 

usertraversalmodel.py 

from baseroot import BaseRoot1 

#用户的根 

class User(BaseRoot1): 

def __getitem__(self,name): 

if 'id' in name: 

return Userid(self.request,'userid',self) 

if name==”blog” 

return Blog(self.request,’blog’,self) 

raise KeyError 

--->出现了KeyError,则转交给view_config定义的url注册,否则继续traval 

#某个用户 

class Userid(Users): 

def __getitem__(self,name): 

raise KeyError 

#某用户的内部文档 

class User_Content(User): 

def __getitem__(self,name): 

raise KeyError 

4.  在traversal基础上实现view路径定义,以及restful,细化页面模块,实现全页面、部分页面(jquery.load)、json输出和本地函 数调用 

,这应该是这个架子最出彩的地方了 

对于页面的渲染方式,综合采用后端的mako模板和前端的mustache模板方式,根据不同情况灵活选择,后端渲染的好处是粒度可以做很细,前端做细了js就 有些乱了,mustache模板也乱,看豆瓣alpha城,那一大溜templete,但前端渲染的好处是减轻服务器压力 

后端渲染: 多个   数据+页面模块    组合成完整页面,mako支持页面母版,可以做一致性页面容器外观 

,这样一个复杂页面下来需要四个层次,1提取页面模块数据,2用模块模板渲染模块,3组合多个模块到页模板,4套用母版 

前端渲染:后端四个渲染层次中,1提取页面模板,加restful输出json,用于jquery.getJSON();2用模块模板渲染后输出string, 加restful输出html片段,用于jquery.load();这样就有两种数据可以取出来,这样后端输出的页面就可以以输出导航和某些细粒度信息为主了 ,backbone提供前端route能力,大多数情况下load后端的html模块就行了,这样,前端代码很舒服。其实,我还是喜欢javascript比p ython多一些,只是我血压高,js代码一多我就头晕 

下面的代码只是举例,不能直接运行,只是看逻辑。。。。 

举例:userview.py 

import ….. 

#url:http://somedomain/user      这是个主页面,mako渲染 

@view_config(context=User,renderer=”user/index.mako”) 

def userlist(request): 

return [{“id”:”…”,”name”:”…”},…….] 

#同时输出json和html 

url:http://somedomain/user/netchtg/blog<http://somedomain/netchtg/blog

或blog.json 

@view_config(name=”blog”,context=Blog,renderer=”blog/bloglist.mako”) 

@view_config(name=”blog.json”,context=Blog,renderer=”json”) 

--->由于mako渲染接收的是dict,同时response json也是用dict,所以 ,正好。。。 

def userbloglist(request): 

return [{…..},{….}….] 

@view_config(name=”bloglist”,context=Blog,renderer=”blog/blogindex.mako”) 

def bloglist(request) 

“””集成渲染,将页面上多个小栏目先渲染后,合并渲染主页面""" 

listtitle=list(request.db.blogtitle.find()) 

#上面只是示例,从数据库中获取模块列表中ID 

for mblogtitle in listtitle: 

#此处引用各标题的html 

restr+=blogtitle(mblogtitle[“id”],request); 

return {“body”:restr} 

blogwidget.py 

#直接response字符串,供jquery.load调用 

@view_config(name=”blogtitle”,context=Blog,renderer=”string”) 

def blogtitle(id=””,request): 

“””客户端可以实用jquery.load来获取html串””” 

#如果没有给定id,则是通过request直接请求的函数,分析url获得id 

… 

idmodel=getblogtitle(id,request) 

#上面是调用数据,分离了函数,是为了函数能单独被request呼叫 

restr=render(“blog/blogtitle.mako”,idmodel) 

return restr 

#数据model或复杂业务逻辑model,输出dict  , 同时支持函数调用和response json 

@view_config(name=”blogtitle.json”,context=Blog,renderer=”json”) 

def getblogtitle(id=””,request) 

“””前端restful调用,直接返回json 

#如果没定义id,分析url获得id ,id号也可以由traversal类分析并压入session中 

idmodel=request.db.blogtitle.find_one({“_id”:id}) 

return idmodel 

view_config 可以通过request_method区分GET POST PUT DELETE,也可以通过POST代理PUT和DELETE

原文链接:http://www.wumii.com/item/12YXIe63Y

作者:zihua | 分类: python | 标签: python | 阅读: 874 | 发布于: 2014-01-20 23时 |