Changeset 5239
- Timestamp:
- 08/25/08 18:00:58 (5 months ago)
- Files:
-
- trunk/tg/decorators.py (modified) (11 diffs)
- trunk/tg/__init__.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/tg/decorators.py
r5146 r5239 1 1 """Decorators use by the TurboGears controllers 2 2 3 These decorators are not traditonal wrappers. They are much simplified from the 4 turbogears 1 decorators, because all they do is regester attributes on 5 the functions they wrap, and then the DecoratedController provides the hooks 3 These decorators are not traditonal wrappers. They are much simplified from the 4 turbogears 1 decorators, because all they do is regester attributes on 5 the functions they wrap, and then the DecoratedController provides the hooks 6 6 needed to support these decorators.""" 7 7 8 8 import formencode 9 9 from paste.util.mimeparse import best_match 10 11 from webob.multidict import MultiDict 12 from webhelpers.paginate import Page 13 from tg.config import Bunch 14 from functools import partial 15 # this can't be tg, as we are circular importing then! 16 from pylons import request 17 from pylons import tmpl_context as c 18 10 19 11 20 class Decoration(object): … … 50 59 require a template. 51 60 """ 52 61 53 62 if content_type is None: 54 63 content_type = '*/*' … … 70 79 content_type = best_match(self.engines.keys(), accept_types) 71 80 engine, template, exclude_names = self.engines[content_type] 72 81 73 82 if 'charset' not in content_type and ( 74 83 content_type.startswith('text') or content_type == 'application/json'): 75 84 content_type = '%s; charset=utf-8' % content_type 76 85 77 86 return content_type, engine, template, exclude_names 78 87 … … 90 99 91 100 class _hook_decorator(object): 92 """SuperClass for all the specific TG2 hook validators. 101 """SuperClass for all the specific TG2 hook validators. 93 102 """ 94 103 # must be overridden by a particular hook … … 121 130 class after_render(_hook_decorator): 122 131 """A list of callables to be run after the template is rendered. 123 132 124 133 Will be run before it is returned returned up the WSGI stack""" 125 134 126 135 hook_name = 'after_render' 127 136 … … 177 186 engine, template = template.split(':', 1) 178 187 elif template: 179 # Use the default templating engine from the config 180 from pylons import config 188 # Use the default templating engine from the config 189 from pylons import config 181 190 engine = config['buffet.template_engines'][0]['engine'] 182 191 else: … … 201 210 202 211 def override_template(controller, template): 203 """Use overide_template in a controller in order to change the 204 template that will be used to render the response dictionary 212 """Use overide_template in a controller in order to change the 213 template that will be used to render the response dictionary 205 214 dynamically.""" 206 215 if hasattr(controller, 'decoration'): … … 212 221 else: 213 222 return 214 223 215 224 text_engine = engines.get('text/html') 216 225 template = template.split(':') … … 221 230 class validate(object): 222 231 """Regesters which validators ought to be applied 223 224 If you want to validate the contents of your form, 232 233 If you want to validate the contents of your form, 225 234 you can use the ``@validate()`` decorator to regester 226 the validators that ought to be called. 227 235 the validators that ought to be called. 236 228 237 :Parameters: 229 238 validators 230 Pass in a dictionary of FormEncode validators. 231 The keys should match the form field names. 239 Pass in a dictionary of FormEncode validators. 240 The keys should match the form field names. 232 241 error_handler 233 242 Pass in the controller method which shoudl be used … … 235 244 form 236 245 Pass in a ToscaWidget based form with validators 237 238 The first positional parameter can either be a dictonary of validators, 246 247 The first positional parameter can either be a dictonary of validators, 239 248 a FormEncode schema validator, or a callable which acts like a FormEncode 240 validator. 241 249 validator. 250 242 251 """ 243 252 def __init__(self, validators=None, error_handler=None, form=None): … … 252 261 deco.validation = self 253 262 return func 263 264 265 def paginate(name, items_per_page=10, use_prefix=False): 266 """ 267 Paginate a given collection. 268 269 This decorator is mainly exposing the functionality 270 of webhelpers.paginate. 271 272 To render the actual pager, use 273 274 ${c.paginators.<name>.pager()} 275 276 where c is the tmpl_context. 277 278 279 :Parameters: 280 name 281 the collection to be paginated. 282 items_per_page 283 the number of items to be rendered. Defaults to 10 284 use_prefix 285 if True, the parameters the paginate 286 decorator renders and reacts to are prefixed with 287 "name_". This allows for multi-pagination. 288 289 """ 290 prefix = "" 291 if use_prefix: 292 prefix = name + "_" 293 own_parameters = dict( 294 page="%spage" % prefix, 295 items_per_page="%sitems_per_page" % prefix 296 ) 297 #@decorator 298 def _d(f): 299 def _w(*args, **kwargs): 300 page = int(kwargs.pop(own_parameters["page"], 1)) 301 real_items_per_page = int(kwargs.pop(own_parameters['items_per_page'], items_per_page)) 302 res = f(*args, **kwargs) 303 if isinstance(res, dict) and name in res: 304 additional_parameters = MultiDict() 305 for key, value in request.str_params.iteritems(): 306 if key not in own_parameters: 307 additional_parameters.add(key, value) 308 collection = res[name] 309 page = Page( 310 collection, 311 page, 312 items_per_page=real_items_per_page, 313 **additional_parameters.dict_of_lists() 314 ) 315 # wrap the pager so that it will render 316 # the proper page-parameter 317 page.pager = partial(page.pager, page_param=own_parameters["page"]) 318 res[name] = page 319 # this is a bit strange - it appears 320 # as if c returns an empty 321 # string for everything it dosen't know. 322 # I didn't find that documented, so I 323 # just put this in here and hope it works. 324 if type(c.paginators) == str: 325 c.paginators = Bunch() 326 c.paginators[name] = page 327 return res 328 return _w 329 return _d 330 331 trunk/tg/__init__.py
r5158 r5239 26 26 * URL Dispatching: Object dispatch 27 27 * Form Handling: ToscaWidgets 28 28 29 29 The zen of TurboGears is:: 30 30 … … 48 48 49 49 Sensible defaults encourage code re-use within TurboGears because 50 they make it possible for a group of TurboGears components to share 50 they make it possible for a group of TurboGears components to share 51 51 assumptions about how things will work. 52 52 """ … … 54 54 from tg.controllers import TGController, redirect, url, use_wsgi_app 55 55 from tg.configuration import config 56 from tg.decorators import validate, expose, override_template 56 from tg.decorators import validate, expose, override_template, paginate 57 57 from tg.flash import flash, get_flash, get_status 58 58 … … 61 61 __all__ = [ 62 62 'expose', 'validate', 'TGController', 'tmpl_context', 'app_globals', 63 'overide_template', 'request', 'response', 'session','TurboGearsApplication', 63 'overide_template', 'request', 'response', 'session','TurboGearsApplication', 64 64 'use_wsgi_app', 'TGApp', 'app_globals' 65 65 ]