2012-07-22 58 views
2

好的,我有我的应用程序,它需要根用户的请求/几乎所有的东西都在使用遍历。使用Traversal制作子应用程序的最佳方式

但我想在该网站的顶部做一个休息api。

所以我有两种选择。我要么分开在两个不同的应用程序,并把其余的应用程序:rest.site.com,或者我可以将其移动到site.com/rest/*traversal

如果我在做“/休息/ *遍历”,我假设我将不得不添加一条名为rest_traversal的路线,其中遍历路径将为*traversal,路线为/rest/*traversal。我曾经为管理页面做过一次。

我想知道是否有最干净的方法来做到这一点。我试图使用virtual_root,但据我所知virtual_root实际上是被添加到遍历的路径。

就像virtual_root = /cms并要求/fun将创建下列路径/cms/fun

我,另一方面希望有/cms/fun变成/fun

回答

1

如果你使用遍历已经,为什么不直接用它来当Pyramid遍历到/rest/时,返回“rest API根”对象?从那里,一切都会自然而然地发挥作

class ApplicationRoot(object): 

    def __getitem__(self, name): 
     if name == "rest": 
      return RestAPIRoot(parent=self, name=name) 
     ... 

如果你的“应用程序树”和“API树”具有相同的孩子,你想对他们有依赖于该树中的子位于的分支,可以使用containment查看注册的不同看法谓词来注册你的API的看法,所以当孩子的“API分支”内,他们将只匹配:

遏制

这个值应该是一个Python类或接口,一个参考 上下文资源的血统中的父对象必须按顺序提供 以查找和调用此视图。您的资源 树中的资源必须具有“位置感知”才能使用此功能。

如果未提供包容,则在决定是否调用可调用的视图时,不会考虑系统中的接口和类。

另一种方法不是构建一个单独的“API树”,而是使用您的“主”应用程序的“URI空间”作为RESTful API。唯一的问题是,GET和可能的POST请求方法已经在您的资源上“取得”,并映射到返回HTML或使用HTTP表单POST的“普通”视图。有许多方法来解决此问题:

  • 注册一个独立的名称的API意见,所以,说GET /users/123将返回HTML和GET /users/123/json将返回一个JSON对象。同样,POST /users/123预计会发布HTTP表单,POST /users/123/json会期望JSON。这种方法的一个好处是,您可以轻松地在GET /users/123/xml上添加XML序列化程序。

  • 使用自定义查看谓词,因此GET /users/123GET /users/123?format=json被路由到不同的视图。其实,还有一个内置的request_param谓词,由于金字塔1.2

  • 使用xhr谓词基于HTTP_X_REQUESTED_WITH页眉或accept谓词来区分请求发送到HTTP_ACCEPT头区分

+0

这是一个好主意,没有考虑重新树立我的树。虽然这是答案的一半。遍历将自然地工作,但会像以前一样匹配相同的视图。 – 2012-07-23 21:19:34

+0

@LoïcFaure-Lacroix:我已经扩大了答案 – Sergey 2012-07-23 22:16:55

+0

nitpick:'match_param'用于匹配路线中的模式。 'request_param'是你想要匹配'request.params'字典的一部分(查询字符串+后主体)。 – 2012-07-24 14:52:51

2

我知道这已回答了,但万一有人来到这里寻找另一种可能的方式,使“subapps”,并在金字塔使用它们,我想指出的是,一些有趣的事情可以用pyramid.wsgi

完成
""" 
example of wsgiapp decorator usage 
http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/api/wsgi.html 
""" 

from pyramid.wsgi import wsgiapp2, wsgiapp 
from pyramid.config import Configurator 
from webob import Request, Response 
import pprint 

# define some apps 


def wsgi_echo(environ, start_response): 
    """pretty print out the environ""" 
    response = Response(body=pprint.pformat({k: v for k, v in environ.items() 
              if k not in ["wsgi.errors", 
                  "wsgi.input", 
                  "SCRIPT_NAME"]})) 
    return response(environ, start_response) 


print Request.blank("/someurl").send(wsgi_echo).body 


# convert wsgi app to a pyramid view callable 
pyramid_echo = wsgiapp(wsgi_echo) 
pyramid_echo_2 = wsgiapp2(wsgi_echo) 

# wire up a pyramid application 

config = Configurator() 
config.add_view(pyramid_echo, name="foo") # /foo 
config.add_view(pyramid_echo, name="bar") # /bar 
config.add_view(pyramid_echo_2, name="foo_2") # /foo 
config.add_view(pyramid_echo_2, name="bar_2") # /bar 
pyramid_app = config.make_wsgi_app() 

#call some urls 
foo_body = Request.blank("/foo").send(pyramid_app).body 
bar_body = Request.blank("/bar").send(pyramid_app).body 
foo_body_2 = Request.blank("/foo_2").send(pyramid_app).body 
bar_body_2 = Request.blank("/bar_2").send(pyramid_app).body 

# both should be different because we arrived at 2 different urls 
assert foo_body != bar_body, "bodies should not be equal" 

# should be equal because wsgiapp2 fixes stuff before calling 
# application in fact there's an additional SCRIPT_NAME in the 
# environment that we are filtering out 
assert foo_body_2 == bar_body_2, "bodies should be equal" 

# so how to pass the path along? like /foo/fuuuu should come back 
# /fuuuu does it 
foo_body = Request.blank("/foo_2/fuuuu").send(pyramid_app).body 
assert "'/fuuuu'," in foo_body, "path didn't get passed along" 


# tldr: a wsgi app that is decorated with wsgiapp2 will recieve data 
# as if it was mounted at "/", any url generation it has to do should 
# take into account the SCRIPT_NAME variable that may arrive in the 
# environ when it is called