问题
Besides the root url request, which will be sent to a view, I want to have a dispatcher that I will route all the requests to different views which I will chose depending on my custom dispatcher's rules.
How can I create a dispatcher? I have read the docs over and over again yet I can not figure it out.
I want to parse the *remainder of url and then dispatch the request accordingly.
回答1:
Pyramid will dispatch the request to a view registered via add_view
or view_config
. If you want to dispatch this again to your own code, just remember that from Pyramid's perspective the renderer/permission defined on the original view will be used... so don't use those. The request effectively enters your Pyramid view, then you have your own mini-framework that will handle it from there.
I suggest thinking about how to dispatch things in the context of Pyramid views, for example the pyramid_rpc
package does some cool stuff to dispatch to views based on the content in the body of an RPC request (not just the URL). See the custom predicate within add_jsonrpc_method to know what I'm talking about.
Anyway, assuming you still want to do your own thing, all you have to do is register a view in Pyramid for whatever pattern you want.
config.add_route('my_framework', '/foo/{the_rest:.*}')
@view_config(route_name='my_framework')
def my_framework_view(request):
url = request.matchdict['the_rest']
# do your frameworky stuff here
if url == 'foo/bar':
return some_other_view(request)
return HTTPNotFound()
Anyway, it should be clear that this is a framework on top of a framework and probably a code smell in a lot of cases.
回答2:
It really depends on the structure or you URLS and your "custom dispatcher rules", but for many cases you can use URL traversal instead of URL dispatch to achieve what you want. Due to the fact that URL traversal uses __getitem__
method of the parent resource, where you can write normal Python code, it may allow you more flexibility.
Example: imagine you have the following URLS:
/food/banana
/food/potato
/food/tomato
/food/apple
and you want to have different views for fruit and vegetables. You can do something like this:
class FoodResource(object):
def __getitem__(self, name):
if name in ["banana", "apple"]:
return FruitResource(self, name)
if name in ["potato", "tomato"]:
return VegetableResource(self, name)
then you can register views for FruitResource
and VegetableResource
:
@view_config(context=FruitResource):
def view_fruit(context, request):
...
@view_config(context=VegetableResource):
def view_vegetable(context, request):
...
You can have different sets of views registered for Fruits and Vegetables, so /foor/banana/make_jam
and /food/apple/make_jam
will be vaild URLs for fruits only, and for vegetables you'll have, say, /food/potato/make_soup
:
@view_config(context=FruitResource, name="make_jam"):
def view_fruit_make_jam(context, request):
...
@view_config(context=VegetableResource, name="make_soup"):
def view_vegetable_make_soup(context, request):
...
Then your FruitResource
and VegetableResource
can have their own __getitem__
methods, so you can have potentially different sets of "subitems" - /food/banana/skin
, /food/banana/flesh
etc, with their own views assigned to them - /food/banana/skin/peel
, /food/banana/flesh/eat
, where peel
and eat
are views registered for imaginary FruitSkinResource
and FruitFleshResource
.
And you can have custom permissions for fruits and vegetables, so accessing /food/apple/make_jam
may require one permission and /food/potato/make_soup
another.
回答3:
I think you could use pyramid's event system docs this is looks like hack but I think it is the easiest way.
来源:https://stackoverflow.com/questions/11139358/pyramid-how-to-create-use-custom-dispatcher