Advanced Practices¶
Advanced routing tools¶
Iktomi provides some additional filters.
A subdomain filter allows to select requests with a given domain or subdomain:
web.cases(
web.subdomain('example.com') | web.cases(
web.match('/', 'index1') | index1,
),
web.subdomain('example.org') | web.cases(
web.match('/', 'index2') | index2,
),
)
You can use multiple subdomain filters in a line to select lower-level subdomains. To specify a base domain chain one subdomain filter before:
web.subdomain('example.com') | web.cases(
# all *.example.com requests get here
web.subdomain('my') | web.cases(
# all *.my.example.com requests get here
...
),
...
)
A static_files handles static files requests and also provides a reverse function to build urls for static files:
static = web.static_files(cfg.STATIC_PATH, cfg.STATIC_URL)
@web.request_filter
def environment(env, data, next_handler):
...
env.url_for_static = static.construct_reverse()
...
app = web.request_filter(environment) | web.cases(
static,
...
)
Handling files is provided for development and testing reasons. You can use it to serve static file on development server, but it is strictly not recommended to use it for this purpose on production (use your web server configuration requests instead of it). Surely, reverse function is recommended to use on both production and development servers.
Custom URL converters¶
You can add custom URL converters by subclassing web.url.Converter. A subclass should provide to_python and to_url methods. First accepts unicode url part and returns any python object. Second does reverse transformation. Note, that url parts are escaped automatically outside URL converter:
class MonthConv(url.Converter):
def to_python(self, value, **kwargs):
try:
return int(value)
except ValueError:
raise ConvertError(self.name, value)
def to_url(self, value):
return str(value)
To include URL converter, pass convs argument to handler constructor:
prefix('/<month:month_num>', convs={'month': MonthConv})
Make an application configurable¶
Configuring env object:
class FrontEnvironment(web.AppEnvironment):
cfg = cfg
cache = memcache_client
def __init__(self, *args, **kwargs):
super(FrontEnvironment, self).__init__(*args, **kwargs)
self.template_data = {}
@cached_property
def url_for(self):
return self.root.build_url
@storage_cached_property
def template(storage):
return BoundTemplate(storage, template_loader)
@storage_method
def render_to_string(storage, template_name, _data, *args, **kwargs):
_data = dict(storage.template_data, **_data)
result = storage.template.render(template_name, _data, *args, **kwargs)
return Markup(result)
@storage_method
def render_to_response(self, template_name, _data,
content_type="text/html"):
_data = dict(self.template_data, **_data)
return self.template.render_to_response(template_name, _data,
content_type=content_type)
@storage_method
def redirect_to(storage, name, qs, **kwargs):
url = storage.url_for(name, **kwargs)
if qs:
url = url.qs_set(qs)
return HTTPSeeOther(location=str(url))
def json(self, data):
return webob.Response(json.dumps(data),
content_type="application/json")
@cached_property
def db(self):
return db_maker()
wsgi_app = Application(app, env_class=FrontEnvironment)
Describe differences between storage_method, storage_property, storage_cached_property, cached_property here.
- BoundTemplate subclassing
- environment handler