Warning
Starting from CubicWeb version 4.0 all code related to generating html views has been moved to the Cube cubicweb_web.
If you want to migrate a project from 3.38 to 4.* while still using all the
html views you need to both install the cubicweb_web cube AND add it to
your dependencies and run add_cube('web')
.
cubicweb_web can be installed from pypi this way:
pip install cubicweb_web
We donât plan to maintain the features in cubicweb_web in the long run; we are moving to a full javascript frontend using both cubicweb_api (which exposes a HTTP API) and @cubicweb/client as a frontend javascript toolkit.
In the long run cubicweb_api will be merged inside of CubicWeb.
URL publishing#
(cubicweb_web.views.urlpublishing
)
Associate urlâs path to view identifier / rql queries.
CubicWeb finds all registered URLPathEvaluators, orders them according
to their priority
attribute and calls their evaluate_path()
method. The first that returns something and doesnât raise a
PathDontMatch
exception wins.
Here is the default evaluator chain:
cubicweb_web.views.urlpublishing.RawPathEvaluator
handles unique url segments that match exactly one of the registered controllerâs __regid__. Urls such as /view?, /edit?, /json? fall in that category;cubicweb_web.views.urlpublishing.EidPathEvaluator
handles unique url segments that are eids (e.g. /1234);cubicweb_web.views.urlpublishing.URLRewriteEvaluator
selects all urlrewriter components, sorts them according to their priority, call theirrewrite()
method, the first one that doesnât raise aKeyError
wins. This is where thecubicweb_web.views.urlrewrite
andcubicweb_web.views.urlrewrite.SimpleReqRewriter
comes into play;cubicweb_web.views.urlpublishing.RestPathEvaluator
handles urls based on entity types and attributes : <etype>((/<attribute name>])?/<attribute value>)? This is whycwuser/carlos
works;cubicweb_web.views.urlpublishing.ActionPathEvaluator
handles any of the previous paths with an additional trailing â/<action>â segment, <action> being one of the registered actionsâ __regid__.
Note
Actionpath executes a query whose results is lost because of redirecting instead of direct traversal.
- class cubicweb_web.views.urlpublishing.URLPublisherComponent(vreg, default_method='view')[source]#
Associate url path to view identifier / rql queries, by applying a chain of urlpathevaluator components.
An evaluator is a URLPathEvaluator subclass with an .evaluate_path method taking the request object and the path to publish as argument. It will either return a publishing method identifier and an rql query on success or raise a PathDontMatch exception on failure. URL evaluators are called according to their priority attribute, with 0 as the greatest priority and greater values as lower priority. The first evaluator returning a result or raising something else than PathDontMatch will stop the handlers chain.
- process(req, path)[source]#
Given a URL (essentially characterized by a path on the server, but additional information may be found in the request object), return a publishing method identifier (e.g. controller) and an optional result set.
- Parameters
req (cubicweb_web.request.CubicWebRequestBase) â the request object
path (str) â the path of the resource to publish. If empty, None or â/â âviewâ is used as the default path.
- Return type
tuple(str, cubicweb.rset.ResultSet or None)
- Returns
the publishing method identifier and an optional result set
- Raises
NotFound â if no handler is able to decode the given path
You can write your own URLPathEvaluator class to handle custom paths. For instance, if you want /my-card-id to redirect to the corresponding cardâs primary view, you would write:
class CardWikiidEvaluator(URLPathEvaluator):
priority = 3 # make it be evaluated *before* RestPathEvaluator
def evaluate_path(self, req, segments):
if len(segments) != 1:
raise PathDontMatch()
rset = req.execute('Any C WHERE C wikiid %(w)s',
{'w': segments[0]})
if len(rset) == 0:
# Raise NotFound if no card is found
raise PathDontMatch()
return None, rset
On the other hand, you can also deactivate some of the standard evaluators in your final application. The only thing you have to do is to unregister them, for instance in a registration_callback in your cube:
def registration_callback(vreg):
vreg.unregister(RestPathEvaluator)
You can even replace the cubicweb_web.views.urlpublishing.URLPublisherComponent
class if you want to customize the whole toolchain process or if you want
to plug into an early enough extension point to control your request
parameters:
class SanitizerPublisherComponent(URLPublisherComponent):
"""override default publisher component to explicitly ignore
unauthorized request parameters in anonymous mode.
"""
unauthorized_form_params = ('rql', 'vid', '__login', '__password')
def process(self, req, path):
if req.session.anonymous_session:
self._remove_unauthorized_params(req)
return super(SanitizerPublisherComponent, self).process(req, path)
def _remove_unauthorized_params(self, req):
for param in req.form.keys():
if param in self.unauthorized_form_params:
req.form.pop(param)
def registration_callback(vreg):
vreg.register_and_replace(SanitizerPublisherComponent, URLPublisherComponent)
- class cubicweb_web.views.urlpublishing.RawPathEvaluator(urlpublisher)[source]#
handle path of the form:
<publishing_method>?parameters...
- class cubicweb_web.views.urlpublishing.EidPathEvaluator(urlpublisher)[source]#
handle path with the form:
<eid>
- class cubicweb_web.views.urlpublishing.URLRewriteEvaluator(urlpublisher)[source]#
tries to find a rewrite rule to apply
URL rewrite rule definitions are stored in URLRewriter objects
URL rewriting#
(cubicweb_web.views.urlrewrite
)
- class cubicweb_web.views.urlrewrite.URLRewriter(req, **extra)[source]#
Base class for URL rewriters.
Url rewriters should have a rules dict that maps an input URI to something that should be used for rewriting.
The actual logic that defines how the rules dict is used is implemented in the rewrite method.
A priority attribute might be used to indicate which rewriter should be tried first. The higher the priority is, the earlier the rewriter will be tried.
- class cubicweb_web.views.urlrewrite.SimpleReqRewriter(req, **extra)[source]#
The SimpleReqRewriters uses a rules dict that maps input URI (regexp or plain string) to a dictionary to update the requestâs form.
If the input uri is a regexp, group substitution is allowed.
- class cubicweb_web.views.urlrewrite.SchemaBasedRewriter(req, **extra)[source]#
Here, the rules dict maps regexps or plain strings to callbacks that will be called with inputurl, uri, req, schema as parameters.
SimpleReqRewriter
is enough for a certain number of simple cases. If it is not sufficient, SchemaBasedRewriter
allows to do more elaborate things.
Here is an example of SimpleReqRewriter
usage with plain string:
from cubicweb_web.views.urlrewrite import SimpleReqRewriter
class TrackerSimpleReqRewriter(SimpleReqRewriter):
rules = [
('/versions', dict(vid='versionsinfo')),
]
When the url is <base_url>/versions, the view with the __regid__ versionsinfo is displayed.
Here is an example of SimpleReqRewriter
usage with regular expressions:
from cubicweb_web.views.urlrewrite import (
SimpleReqRewriter, rgx)
class BlogReqRewriter(SimpleReqRewriter):
rules = [
(rgx('/blogentry/([a-z_]+)\.rss'),
dict(rql=('Any X ORDERBY CD DESC LIMIT 20 WHERE X is BlogEntry,'
'X creation_date CD, X created_by U, '
'U login "%(user)s"'
% {'user': r'\1'}), vid='rss'))
]
When a url matches the regular expression, the view with the __regid__ rss which match the result set is displayed.
To deal with URL rewriting with an underlying RQL query, it is possible to specify the behaviour in the case of an empty rset with the option empty_rset_raises_404.
The following example shows a SimpleReqRewriter
usage with the
empty_rset_raises_404 option set to True.
In this case, the path mycwetypeurl/pouet will return a 404. Without this option,
it would return a 200.
from cubicweb_web.views.urlrewrite import (
SimpleReqRewriter, rgx)
class MyRewriter(SimpleReqRewriter):
rules = [(rgx(r'/mycwetypeurl/([^/]+)'),
dict(vid='primary',
rql=r'Any T WHERE T is CWEType, T name "\1"',
empty_rset_raises_404=True),)]
Here is an example of SchemaBasedRewriter
usage:
from cubicweb_web.views.urlrewrite import (
SchemaBasedRewriter, rgx, build_rset)
class TrackerURLRewriter(SchemaBasedRewriter):
rules = [
(rgx('/project/([^/]+)/([^/]+)/tests'),
build_rset(rql='Version X WHERE X version_of P, P name %(project)s, X num %(num)s',
rgxgroups=[('project', 1), ('num', 2)], vid='versiontests')),
]