最近立项一个项目,项目基本需求如下:
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