Changeset 5239

Show
Ignore:
Timestamp:
08/25/08 18:00:58 (5 months ago)
Author:
deets
Message:

added paginate decorator

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tg/decorators.py

    r5146 r5239  
    11"""Decorators use by the TurboGears controllers 
    22 
    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  
     3These decorators are not traditonal wrappers.  They  are much simplified from the 
     4turbogears 1 decorators, because all they do is regester attributes on 
     5the functions they wrap, and then the DecoratedController provides the hooks 
    66needed to support these decorators.""" 
    77 
    88import formencode 
    99from paste.util.mimeparse import best_match 
     10 
     11from webob.multidict import MultiDict 
     12from webhelpers.paginate import Page 
     13from tg.config import Bunch 
     14from functools import partial 
     15# this can't be tg, as we are circular importing then! 
     16from pylons import request 
     17from pylons import tmpl_context as c 
     18 
    1019 
    1120class Decoration(object): 
     
    5059        require a template. 
    5160        """ 
    52          
     61 
    5362        if content_type is None: 
    5463            content_type = '*/*' 
     
    7079        content_type = best_match(self.engines.keys(), accept_types) 
    7180        engine, template, exclude_names = self.engines[content_type] 
    72          
     81 
    7382        if 'charset' not in content_type and ( 
    7483           content_type.startswith('text') or content_type  == 'application/json'): 
    7584            content_type = '%s; charset=utf-8' % content_type 
    76          
     85 
    7786        return content_type, engine, template, exclude_names 
    7887 
     
    9099 
    91100class _hook_decorator(object): 
    92     """SuperClass for all the specific TG2 hook validators.  
     101    """SuperClass for all the specific TG2 hook validators. 
    93102    """ 
    94103    # must be overridden by a particular hook 
     
    121130class after_render(_hook_decorator): 
    122131    """A list of callables to be run after the template is rendered. 
    123      
     132 
    124133    Will be run before it is returned returned up the WSGI stack""" 
    125      
     134 
    126135    hook_name = 'after_render' 
    127136 
     
    177186            engine, template = template.split(':', 1) 
    178187        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 
    181190            engine = config['buffet.template_engines'][0]['engine'] 
    182191        else: 
     
    201210 
    202211def 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 
    205214    dynamically.""" 
    206215    if hasattr(controller, 'decoration'): 
     
    212221    else: 
    213222        return 
    214      
     223 
    215224    text_engine = engines.get('text/html') 
    216225    template = template.split(':') 
     
    221230class validate(object): 
    222231    """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, 
    225234    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 
    228237    :Parameters: 
    229238      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. 
    232241      error_handler 
    233242        Pass in the controller method which shoudl be used 
     
    235244      form 
    236245        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, 
    239248    a FormEncode schema validator, or a callable which acts like a FormEncode 
    240     validator.  
    241      
     249    validator. 
     250 
    242251    """ 
    243252    def __init__(self, validators=None, error_handler=None, form=None): 
     
    252261        deco.validation = self 
    253262        return func 
     263 
     264 
     265def 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  
    2626    * URL Dispatching: Object dispatch 
    2727    * Form Handling: ToscaWidgets 
    28      
     28 
    2929The zen of TurboGears is:: 
    3030 
     
    4848 
    4949Sensible defaults encourage code re-use within TurboGears because 
    50 they make it possible for a group of TurboGears components to share  
     50they make it possible for a group of TurboGears components to share 
    5151assumptions about how things will work. 
    5252""" 
     
    5454from tg.controllers import TGController, redirect, url, use_wsgi_app 
    5555from tg.configuration import config 
    56 from tg.decorators import validate, expose, override_template 
     56from tg.decorators import validate, expose, override_template, paginate 
    5757from tg.flash import flash, get_flash, get_status 
    5858 
     
    6161__all__ = [ 
    6262    'expose', 'validate', 'TGController', 'tmpl_context', 'app_globals', 
    63     'overide_template', 'request', 'response', 'session','TurboGearsApplication',  
     63    'overide_template', 'request', 'response', 'session','TurboGearsApplication', 
    6464    'use_wsgi_app', 'TGApp', 'app_globals' 
    6565]