ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 02.01.2026
Просмотров: 2746
Скачиваний: 0
CHAPTER
TWENTYFOUR
RESOURCES
A resource is an object that represents a “place” in a tree related to your application. Every Pyramid application has at least one resource object: the root resource. Even if you don’t define a root resource manually, a default one is created for you. The root resource is the root of a resource tree. A resource tree is a set of nested dictionary-like objects which you can use to represent your website’s structure.
In an application which uses traversal to map URLs to code, the resource tree structure is used heavily to map each URL to a view callable. When traversal is used, Pyramid will walk through the resource tree by traversing through its nested dictionary structure in order to find a context resource. Once a context resource is found, the context resource and data in the request will be used to find a view callable.
In an application which uses URL dispatch, the resource tree is only used indirectly, and is often “invisible” to the developer. In URL dispatch applications, the resource “tree” is often composed of only the root resource by itself. This root resource sometimes has security declarations attached to it, but is not required to have any. In general, the resource tree is much less important in applications that use URL dispatch than applications that use traversal.
In “Zope-like” Pyramid applications, resource objects also often store data persistently, and offer methods related to mutating that persistent data. In these kinds of applications, resources not only represent the site structure of your website, but they become the domain model of the application.
Also:
•The context and containment predicate arguments to add_view() (or a view_config() decorator) reference a resource class or resource interface.
•A root factory returns a resource.
•A resource is exposed to view code as the context of a view.
•Various helpful Pyramid API methods expect a resource as an argument (e.g. resource_url() and others).
261
24. RESOURCES
24.1 Defining a Resource Tree
When traversal is used (as opposed to a purely url dispatch based application), Pyramid expects to be able to traverse a tree composed of resources (the resource tree). Traversal begins at a root resource, and descends into the tree recursively, trying each resource’s __getitem__ method to resolve a path segment to another resource object. Pyramid imposes the following policy on resource instances in the tree:
•A container resource (a resource which contains other resources) must supply a __getitem__ method which is willing to resolve a unicode name to a sub-resource. If a sub-resource by a particular name does not exist in a container resource, __getitem__ method of the container resource must raise a KeyError. If a sub-resource by that name does exist, the container’s __getitem__ should return the sub-resource.
•Leaf resources, which do not contain other resources, must not implement a __getitem__, or if they do, their __getitem__ method must always raise a KeyError.
See Traversal for more information about how traversal works against resource instances.
Here’s a sample resource tree, represented by a variable named root:
1class Resource(dict):
2pass
3
4root = Resource({’a’:Resource({’b’:Resource({’c’:Resource()})})})
The resource tree we’ve created above is represented by a dictionary-like root object which has a single child named ’a’. ’a’ has a single child named ’b’, and ’b’ has a single child named ’c’, which has no children. It is therefore possible to access the ’c’ leaf resource like so:
1 root[’a’][’b’][’c’]
If you returned the above root object from a root factory, the path /a/b/c would find the ’c’ object in the resource tree as the result of traversal.
In this example, each of the resources in the tree is of the same class. This is not a requirement. Resource elements in the tree can be of any type. We used a single class to represent all resources in the tree for the sake of simplicity, but in a “real” app, the resources in the tree can be arbitrary.
Although the example tree above can service a traversal, the resource instances in the above example are not aware of location, so their utility in a “real” application is limited. To make best use of built-in Pyramid API facilities, your resources should be “location-aware”. The next section details how to make resources location-aware.
262
24.2. LOCATION-AWARE RESOURCES
24.2 Location-Aware Resources
In order for certain Pyramid location, security, URL-generation, and traversal APIs to work properly against the resources in a resource tree, all resources in the tree must be location -aware. This means they must have two attributes: __parent__ and __name__.
The __parent__ attribute of a location-aware resource should be a reference to the resource’s parent resource instance in the tree. The __name__ attribute should be the name with which a resource’s parent refers to the resource via __getitem__.
The __parent__ of the root resource should be None and its __name__ should be the empty string. For instance:
1 class MyRootResource(object):
2__name__ = ’’
3__parent__ = None
A resource returned from the root resource’s __getitem__ method should have a __parent__ attribute that is a reference to the root resource, and its __name__ attribute should match the name by which it is reachable via the root resource’s __getitem__. A container resource within the root resource should have a __getitem__ that returns resources with a __parent__ attribute that points at the container, and these subobjects should have a __name__ attribute that matches the name by which they are retrieved from the container via __getitem__. This pattern continues recursively “up” the tree from the root.
The __parent__ attributes of each resource form a linked list that points “downwards” toward the root. This is analogous to the .. entry in filesystem directories. If you follow the __parent__ values from any resource in the resource tree, you will eventually come to the root resource, just like if you keep executing the cd .. filesystem command, eventually you will reach the filesystem root directory.
latex-warning.png
If your root resource has a __name__ argument that is not None or the empty string, URLs returned by the resource_url() function and paths generated by the resource_path() and resource_path_tuple() APIs will be generated improperly. The value of __name__ will be prepended to every path and URL generated (as opposed to a single leading slash or empty tuple element).
263
24. RESOURCES
Using pyramid_traversalwrapper
If you’d rather not manage the __name__ and __parent__ attributes of your resources “by hand”, an add-on package named pyramid_traversalwrapper can help.
In order to use this helper feature, you must first install the pyramid_traversalwrapper package (available via PyPI), then register its ModelGraphTraverser as the traversal policy, rather than the default Pyramid traverser. The package contains instructions for doing so.
Once Pyramid is configured with this feature, you will no longer need to manage the __parent__ and __name__ attributes on resource objects “by hand”. Instead, as necessary, during traversal Pyramid will wrap each resource (even the root resource) in a LocationProxy which will dynamically assign a __name__ and a __parent__ to the traversed resource (based on the last traversed resource and the name supplied to __getitem__). The root resource will have a __name__ attribute of None and a __parent__ attribute of None.
Applications |
which |
use tree-walking Pyramid |
APIs require location-aware resources. |
||
These APIs |
include |
(but are not limited to) |
resource_url(), find_resource(), |
||
find_root(), find_interface(), resource_path(), |
resource_path_tuple(), |
||||
or traverse(), |
virtual_root(), |
and |
(usually) |
has_permission() and |
|
principals_allowed_by_permission(). |
|
|
|
||
In general, since so much Pyramid infrastructure depends on location-aware resources, it’s a good idea to make each resource in your tree location-aware.
24.3 Generating The URL Of A Resource
If your resources are location aware, you can use the pyramid.request.Request.resource_url()
API to generate a URL for the resource. This URL will use the resource’s position in the parent tree to create a resource path, and it will prefix the path with the current application URL to form a fully-qualified URL with the scheme, host, port, and path. You can also pass extra arguments to resource_url() to influence the generated URL.
The simplest call to resource_url() looks like this:
1 url = request.resource_url(resource)
The request in the above example is an instance of a Pyramid request object.
If the resource referred to as resource in the above example was the root resource, and the host that was used to contact the server was example.com, the URL generated would be
264
24.3. GENERATING THE URL OF A RESOURCE
http://example.com/. However, if the resource was a child of the root resource named a, the generated URL would be http://example.com/a/.
A slash is appended to all resource URLs when resource_url() is used to generate them in this simple manner, because resources are “places” in the hierarchy, and URLs are meant to be clicked on to be visited. Relative URLs that you include on HTML pages rendered as the result of the default view of a resource are more apt to be relative to these resources than relative to their parent.
You can also pass extra elements to resource_url():
1 url = request.resource_url(resource, ’foo’, ’bar’)
If |
the resource referred to as resource in |
the |
above example |
was the root resource, and |
the |
host that was used to contact the server |
was |
example.com, |
the URL generated would |
be http://example.com/foo/bar. Any number of extra elements can be passed to resource_url() as extra positional arguments. When extra elements are passed, they are appended to the resource’s URL. A slash is not appended to the final segment when elements are passed.
You can also pass a query string:
1 url = request.resource_url(resource, query={’a’:’1’})
If the resource referred to as resource in the above example was the root resource, and the host that was used to contact the server was example.com, the URL generated would be http://example.com/?a=1.
When a virtual root is active, the URL generated by resource_url() for a resource may be “shorter” than its physical tree path. See Virtual Root Support for more information about virtually rooting a resource.
For more information about generating resource URLs, see the documentation for pyramid.request.Request.resource_url().
24.3.1 Overriding Resource URL Generation
If a resource object implements a __resource_url__ method, this method will be called when resource_url() is called to generate a URL for the resource, overriding the default URL returned for the resource by resource_url().
The __resource_url__ hook is passed two arguments: request and info. request is the request object passed to resource_url(). info is a dictionary with two keys:
265
24. RESOURCES
physical_path A string representing the “physical path” computed for the resource, as defined by pyramid.traversal.resource_path(resource). It will begin and end with a slash.
virtual_path A string representing the “virtual path” computed for the resource, as defined by Virtual Root Support. This will be identical to the physical path if virtual rooting is not enabled. It will begin and end with a slash.
app_url A string representing the application URL generated during request.resource_url. It will not end with a slash. It represents a potentially customized URL prefix, containing potentially custom scheme, host and port information passed by the user to request.resource_url. It should be preferred over use of request.application_url.
The __resource_url__ method of a resource should return a string representing a URL. If it cannot override the default, it should return None. If it returns None, the default URL will be returned.
Here’s an example __resource_url__ method.
1
2
3
class Resource(object):
def __resource_url__(self, request, info): return info[’app_url’] + info[’virtual_path’]
The above example actually just generates and returns the default URL, which would have been what was generated by the default resource_url machinery, but your code can perform arbitrary logic as necessary. For example, your code may wish to override the hostname or port number of the generated URL.
Note that the URL generated by __resource_url__ should be fully qualified, should end in a slash, and should not contain any query string or anchor elements (only path elements) to work with resource_url().
24.4 Generating the Path To a Resource
pyramid.traversal.resource_path() returns a string object representing the absolute physical path of the resource object based on its position in the resource tree. Each segment of the path is separated with a slash character.
1
2
from pyramid.traversal import resource_path url = resource_path(resource)
266
24.5. FINDING A RESOURCE BY PATH
If resource in the example above was accessible in the tree as root[’a’][’b’], the above example would generate the string /a/b.
Any positional arguments passed in to resource_path() will be appended as path segments to the end of the resource path.
1
2
from pyramid.traversal import resource_path url = resource_path(resource, ’foo’, ’bar’)
If resource in the example above was accessible in the tree as root[’a’][’b’], the above example would generate the string /a/b/foo/bar.
The resource passed in must be location-aware.
The presence or absence of a virtual root has no impact on the behavior of resource_path().
24.5 Finding a Resource by Path
If you have a string path to a resource, you can grab the resource from that place in the application’s resource tree using pyramid.traversal.find_resource().
You can resolve an absolute path by passing a string prefixed with a / as the path argument:
1
2
from pyramid.traversal import find_resource url = find_resource(anyresource, ’/path’)
Or you can resolve a path relative to the resource you pass in by passing a string that isn’t prefixed by /:
1
2
from pyramid.traversal import find_resource url = find_resource(anyresource, ’path’)
Often the paths you pass to find_resource() are generated by the resource_path() API. These APIs are “mirrors” of each other.
If the path cannot be resolved when calling find_resource() (if the respective resource in the tree does not exist), a KeyError will be raised.
See the pyramid.traversal.find_resource() documentation for more information about resolving a path to a resource.
267