pylons.templating
Covered: 160 lines
Missed: 72 lines
Skipped 102 lines
Percent: 68 %

      1

    """Render functions and helpers

      2

      3

    Render functions and helpers

      4

    ============================

      5

      6

    :mod:`pylons.templating` includes several basic render functions,

      7

    :func:`render_mako`, :func:`render_genshi` and :func:`render_jinja2`

      8

    that render templates from the file-system with the assumption that

      9

    variables intended for the will be attached to :data:`tmpl_context`

     10

    (hereafter referred to by its short name of :data:`c` which it is

     11

    commonly imported as).

     12

     13

    The default render functions work with the template language loader

     14

    object that is setup on the :data:`app_globals` object in the project's

     15

    :file:`config/environment.py`.

     16

     17

    Usage

     18

    -----

     19

     20

    Generally, one of the render functions will be imported in the

     21

    controller. Variables intended for the template are attached to the

     22

    :data:`c` object. The render functions return unicode (they actually

     23

    return :class:`~webhelpers.html.literal` objects, a subclass of

     24

    unicode).

     25

     26

    .. admonition :: Tip

     27

     28

        :data:`tmpl_context` (template context) is abbreviated to :data:`c`

     29

        instead of its full name since it will likely be used extensively

     30

        and it's much faster to use :data:`c`. Of course, for users that

     31

        can't tolerate one-letter variables, feel free to not import

     32

        :data:`tmpl_context` as :data:`c` since both names are available in

     33

        templates as well.

     34

     35

    Example of rendering a template with some variables::

     36

     37

        from pylons import tmpl_context as c

     38

        from pylons.templating import render_mako as render

     39

     40

        from sampleproject.lib.base import BaseController

     41

     42

        class SampleController(BaseController):

     43

     44

            def index(self):

     45

                c.first_name = "Joe"

     46

                c.last_name = "Smith"

     47

                return render('/some/template.mako')

     48

     49

    And the accompanying Mako template:

     50

     51

    .. code-block:: mako

     52

     53

        Hello ${c.first name}, I see your lastname is ${c.last_name}!

     54

     55

    Your controller will have additional default imports for commonly used

     56

    functions.

     57

     58

    Template Globals

     59

    ----------------

     60

     61

    Templates rendered in Pylons should include the default Pylons globals

     62

    as the :func:`render_mako`, :func:`render_genshi` and

     63

    :func:`render_jinja2` functions. The full list of Pylons globals that

     64

    are included in the template's namespace are:

     65

     66

    - :term:`c` -- Template context object

     67

    - :term:`tmpl_context` -- Template context object

     68

    - :data:`config` -- Pylons :class:`~pylons.configuration.PylonsConfig`

     69

      object (acts as a dict)

     70

    - :term:`app_globals` -- Project application globals object

     71

    - :term:`h` -- Project helpers module reference

     72

    - :data:`request` -- Pylons :class:`~pylons.controllers.util.Request`

     73

      object for this request

     74

    - :data:`response` -- Pylons :class:`~pylons.controllers.util.Response`

     75

      object for this request

     76

    - :class:`session` -- Pylons session object (unless Sessions are

     77

      removed)

     78

    - :class:`url <routes.util.URLGenerator>` -- Routes url generator

     79

      object

     80

    - :class:`translator` -- Gettext translator object configured for

     81

      current locale

     82

    - :func:`ungettext` -- Unicode capable version of gettext's ngettext

     83

      function (handles plural translations)

     84

    - :func:`_` -- Unicode capable gettext translate function

     85

    - :func:`N_` -- gettext no-op function to mark a string for

     86

      translation, but doesn't actually translate

     87

     88

    Configuring the template language

     89

    ---------------------------------

     90

     91

    The template engine is created in the projects

     92

    ``config/environment.py`` and attached to the ``app_globals`` (g)

     93

    instance. Configuration options can be directly passed into the

     94

    template engine, and are used by the render functions.

     95

     96

    .. warning::

     97

     98

        Don't change the variable name on :data:`app_globals` that the

     99

        template loader is attached to if you want to use the render_*

    100

        functions that :mod:`pylons.templating` comes with. The render_*

    101

        functions look for the template loader to render the template.

    102

    103

    """

    104

    import logging

    105

    106

    from webhelpers.html import literal

    107

    108

    import pylons

    109

    110

    __all__ = ['render_genshi', 'render_jinja2', 'render_mako', 'render_response']

    111

    112

    PYLONS_VARS = ['c', 'app_globals', 'config', 'h', 'render', 'request',

    113

                   'session', 'translator', 'ungettext', '_', 'N_']

    114

    115

    log = logging.getLogger(__name__)

    116

    117

    def pylons_globals():

    118

        """Create and return a dictionary of global Pylons variables

    119

    120

        Render functions should call this to retrieve a list of global

    121

        Pylons variables that should be included in the global template

    122

        namespace if possible.

    123

    124

        Pylons variables that are returned in the dictionary:

    125

            ``c``, ``h``, ``_``, ``N_``, config, request, response,

    126

            translator, ungettext, ``url``

    127

    128

        If SessionMiddleware is being used, ``session`` will also be

    129

        available in the template namespace.

    130

    131

        """

    132

        conf = pylons.config._current_obj()

    133

        c = pylons.tmpl_context._current_obj()

    134

        app_globals = conf.get('pylons.app_globals')

    135

        pylons_vars = dict(

    136

            c=c,

    137

            tmpl_context=c,

    138

            config=conf,

    139

            app_globals=app_globals,

    140

            h=conf.get('pylons.h'),

    141

            request=pylons.request._current_obj(),

    142

            response=pylons.response._current_obj(),

    143

            url=pylons.url._current_obj(),

    144

            translator=pylons.translator._current_obj(),

    145

            ungettext=pylons.i18n.ungettext,

    146

            _=pylons.i18n._,

    147

            N_=pylons.i18n.N_

    148

        )

    149

    150

        # If the session was overriden to be None, don't populate the session

    151

        # var

    152

        econf = pylons.config['pylons.environ_config']

    153

        if 'beaker.session' in pylons.request.environ or \

    154

            ('session' in econf and econf['session'] in pylons.request.environ):

    155

            pylons_vars['session'] = pylons.session._current_obj()

    156

        log.debug("Created render namespace with pylons vars: %s", pylons_vars)

    157

        return pylons_vars

    158

    159

    160

    def cached_template(template_name, render_func, ns_options=(),

    161

                        cache_key=None, cache_type=None, cache_expire=None,

    162

                        **kwargs):

    163

        """Cache and render a template

    164

    165

        Cache a template to the namespace ``template_name``, along with a

    166

        specific key if provided.

    167

    168

        Basic Options

    169

    170

        ``template_name``

    171

            Name of the template, which is used as the template namespace.

    172

        ``render_func``

    173

            Function used to generate the template should it no longer be

    174

            valid or doesn't exist in the cache.

    175

        ``ns_options``

    176

            Tuple of strings, that should correspond to keys likely to be

    177

            in the ``kwargs`` that should be used to construct the

    178

            namespace used for the cache. For example, if the template

    179

            language supports the 'fragment' option, the namespace should

    180

            include it so that the cached copy for a template is not the

    181

            same as the fragment version of it.

    182

    183

        Caching options (uses Beaker caching middleware)

    184

    185

        ``cache_key``

    186

            Key to cache this copy of the template under.

    187

        ``cache_type``

    188

            Valid options are ``dbm``, ``file``, ``memory``, ``database``,

    189

            or ``memcached``.

    190

        ``cache_expire``

    191

            Time in seconds to cache this template with this ``cache_key``

    192

            for. Or use 'never' to designate that the cache should never

    193

            expire.

    194

    195

        The minimum key required to trigger caching is

    196

        ``cache_expire='never'`` which will cache the template forever

    197

        seconds with no key.

    198

    199

        """

    200

        # If one of them is not None then the user did set something

    201

        if cache_key is not None or cache_expire is not None or cache_type \

    202

            is not None:

    203

    204

            if not cache_type:

    205

                cache_type = 'dbm'

    206

            if not cache_key:

    207

                cache_key = 'default'

    208

            if cache_expire == 'never':

    209

                cache_expire = None

    210

            namespace = template_name

    211

            for name in ns_options:

    212

                namespace += str(kwargs.get(name))

    213

            cache = pylons.cache.get_cache(namespace, type=cache_type)

    214

            content = cache.get_value(cache_key, createfunc=render_func,

    215

                expiretime=cache_expire)

    216

            return content

    217

        else:

    218

            return render_func()

    219

    220

    221

    def render_mako(template_name, extra_vars=None, cache_key=None,

    222

                    cache_type=None, cache_expire=None):

    223

        """Render a template with Mako

    224

    225

        Accepts the cache options ``cache_key``, ``cache_type``, and

    226

        ``cache_expire``.

    227

    228

        """

    229

        # Create a render callable for the cache function

    230

        def render_template():

    231

            # Pull in extra vars if needed

    232

            globs = extra_vars or {}

    233

    234

            # Second, get the globals

    235

            globs.update(pylons_globals())

    236

    237

            # Grab a template reference

    238

            template = globs['app_globals'].mako_lookup.get_template(template_name)

    239

    240

            return literal(template.render_unicode(**globs))

    241

    242

        return cached_template(template_name, render_template, cache_key=cache_key,

    243

                               cache_type=cache_type, cache_expire=cache_expire)

    244

    245

    246

    def render_mako_def(template_name, def_name, cache_key=None,

    247

                        cache_type=None, cache_expire=None, **kwargs):

    248

        """Render a def block within a Mako template

    249

    250

        Takes the template name, and the name of the def within it to call.

    251

        If the def takes arguments, they should be passed in as keyword

    252

        arguments.

    253

    254

        Example::

    255

    256

            # To call the def 'header' within the 'layout.mako' template

    257

            # with a title argument

    258

            render_mako_def('layout.mako', 'header', title='Testing')

    259

    260

        Also accepts the cache options ``cache_key``, ``cache_type``, and

    261

        ``cache_expire``.

    262

    263

        """

    264

        # Create a render callable for the cache function

    265

        def render_template():

    266

            # Pull in extra vars if needed

    267

            globs = kwargs or {}

    268

    269

            # Second, get the globals

    270

            globs.update(pylons_globals())

    271

    272

            # Grab a template reference

    273

            template = globs['app_globals'].mako_lookup.get_template(

    274

                template_name).get_def(def_name)

    275

    276

            return literal(template.render_unicode(**globs))

    277

    278

        return cached_template(template_name, render_template, cache_key=cache_key,

    279

                               cache_type=cache_type, cache_expire=cache_expire)

    280

    281

    282

    def render_genshi(template_name, extra_vars=None, cache_key=None,

    283

                      cache_type=None, cache_expire=None, method='xhtml'):

    284

        """Render a template with Genshi

    285

    286

        Accepts the cache options ``cache_key``, ``cache_type``, and

    287

        ``cache_expire`` in addition to method which are passed to Genshi's

    288

        render function.

    289

    290

        """

    291

        # Create a render callable for the cache function

    292

        def render_template():

    293

            # Pull in extra vars if needed

    294

            globs = extra_vars or {}

    295

    296

            # Second, get the globals

    297

            globs.update(pylons_globals())

    298

    299

            # Grab a template reference

    300

            template = globs['app_globals'].genshi_loader.load(template_name)

    301

    302

            return literal(template.generate(**globs).render(method=method,

    303

                                                             encoding=None))

    304

    305

        return cached_template(template_name, render_template, cache_key=cache_key,

    306

                               cache_type=cache_type, cache_expire=cache_expire,

    307

                               ns_options=('method'), method=method)

    308

    309

    310

    def render_jinja2(template_name, extra_vars=None, cache_key=None,

    311

                     cache_type=None, cache_expire=None):

    312

        """Render a template with Jinja2

    313

    314

        Accepts the cache options ``cache_key``, ``cache_type``, and

    315

        ``cache_expire``.

    316

    317

        """

    318

        # Create a render callable for the cache function

    319

        def render_template():

    320

            # Pull in extra vars if needed

    321

            globs = extra_vars or {}

    322

    323

            # Second, get the globals

    324

            globs.update(pylons_globals())

    325

    326

            # Grab a template reference

    327

            template = \

    328

                globs['app_globals'].jinja2_env.get_template(template_name)

    329

    330

            return literal(template.render(**globs))

    331

    332

        return cached_template(template_name, render_template, cache_key=cache_key,

    333

                               cache_type=cache_type, cache_expire=cache_expire)

    334