I'm currently using the Pyramid web framework and I have it configured with Mako templates. I know that I can render a template as a string from within a view method (Pyramid - Is it possible to render my mako template as a string within my view callable?), however, I was wondering if it is possible to get the actual template object from within a view and not just a function to render the template.
Looking through the Pyramid source code, in mako_templating.py I see that the default TemplateLookup class is overridden with a lookup method for Pyramid. Is there anyway to access this lookup object primarily so I can use the get_template function that is part of it?
Thanks for any direction on this issue.
This level of introspection is not officially supported by Pyramid's rendering API. That being said, here's a way to do it. This is completely undocumented, unsupported, private, etc, etc. Meaning, don't come complaining when this stops working.
from pyramid.mako_templating import IMakoLookup
lookup = request.registry.queryUtility(IMakoLookup, name='mako.')
tmpl = lookup.get_template('myapp:templates/foo.mako')
opts = {} # rendering context
result = tmpl.render_unicode(**opts)
This works for me:
from pyramid.renderers import render
sRenderedStuff = render('path/to/template.mak',dContext)
An example use case would be something like this:
sEmailHtml = render("email/welcome_message_html.mak",dContext)
With the following line in your pyramid settings file:
mako.directories = your_app:templates
The template is fetched from your_app/templates/email/welcome_message.html. All inheritance and include tags work just as they would for templates rendered to a view response.
Related
I know jinja2 is the default built-in template engine for Flask. My question is:
Is it possible to integreate Chameleon with Flask ?
If so, how can I do that ?
This is how I did. I wrap the response string in a method..
from chameleon import PageTemplate
def execute_page(template_str, page):
# Irrelevant
template = PageTemplate(template_str)
return template.render(page=page)
then consume the method and return the HTTPResponse. Hence, I completely skip render_template(template_file_name) approach.
My question is: Is it the proper (Pythonic, Flask) way to do?
So I found this answer regarding setting session variables in a pyramid view file, and then later accessing it in a mako template. ( How to access session variable in Mako template and Pyramid? )
I wanted to know if you could do it the other way around. So instead of:
Pyramid view.py
def thisView(request):
session = request.session
session['selectedclientid'] = 'test' #selectedclient.id
session.save()
webpage.mako
${request.session['selectedclientid']}
Can I swap it so I can do this instead?
webpage.mako
${request.session['selectedclientid'] = '5'}
Pyramid view.py
def thisView(request):
someLogicOn(session['selectedclientid'])
So far I have been unsuccessful in making it work and I'm not sure if it's just due to a lack of understanding how to do it or if it's something that just can't be done. Any advice would be great!
In the typical rendering workflow, the view executes before the renderer. It's not clear how you are intending to correct for that. It's possible to do if you call render yourself within the view, I guess, so I'll show that.
webpage.mako:
<%
request.session['selectedClientId'] = '5'
%>
code:
def thisView(request):
response = render_to_response('webpage.mako', {}, request=request)
someLogicOn(request.session['selectedClientId'])
return response
This is logically a little backward though, so you might want to think twice about what you're doing.
I've tried several different ways a while ago, each of them gave a different exception, so I gave up and decided to manually write filters when I need them. But I'm missing the native escapejs and other useful but simple filters.
There are several related questions and answers, but as far as I see none of them gives a seamless way to implement this. I guess the main problem is that django filters routines are tied too much to the django environment.
Please answer only if you managed to use built-in django filters in the Appengine SDK environment, from my experience it's harder compared to a normal environment, as Appengine environment is limited
Template tags in the Django template engine are simple functions that accept values and parameters. They can all be accessed directly in the source code.
This is output from IPython:
In [173]: from django.template.defaultfilters import date
In [174]: date??
Type: function
String Form:<function date at 0xa2935f0>
File: /usr/local/python/thor/lib/python2.7/site-packages/django/template/defaultfilters.py
Definition: date(value, arg=None)
Source:
#register.filter(expects_localtime=True, is_safe=False)
def date(value, arg=None):
"""Formats a date according to the given format."""
if not value:
return u''
if arg is None:
arg = settings.DATE_FORMAT
try:
return formats.date_format(value, arg)
except AttributeError:
try:
return format(value, arg)
except AttributeError:
return ''
Most of the Django-specific magic resides in the decorator (register.filter) and in the way that the language resolves calls when you type {% load <template library> %} in your template. Look for the definitions in <module>.templatetags modules. Built-ins are located in django.template.defaulttags and django.template.defaultfilters.
If Jinja2 has a way to define new template filters (which it probably does), then you could simply wrap handmade template filters to actual Django functions.
So basically, just create Jinja2 filters that point to the actual Django function definitions.
Edit:
If you do not have access to the actual Django functions, just copy-paste the source code and remove or adapt Django-specific stuff.
The escapejs filter is actually a call to this function in django.utils.html:
_base_js_escapes = (
('\\', r'\u005C'),
('\'', r'\u0027'),
('"', r'\u0022'),
('>', r'\u003E'),
('<', r'\u003C'),
('&', r'\u0026'),
('=', r'\u003D'),
('-', r'\u002D'),
(';', r'\u003B'),
(u'\u2028', r'\u2028'),
(u'\u2029', r'\u2029')
)
# Escape every ASCII character with a value less than 32.
_js_escapes = (_base_js_escapes +
tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
def escapejs(value):
"""Hex encodes characters for use in JavaScript strings."""
for bad, good in _js_escapes:
value = mark_safe(force_unicode(value).replace(bad, good))
return value
I alluded to this in my comment, but I'll be more specific here since I have more space. Django is an end-to-end web application framework, which happens to include its own template language, that for lack of a better term is just called the "Django template language". All the template tags and filters in the docs are specific to that language.
If you choose to use Jinja2, you choose to use that template language's structures to the exclusion of Django's. (Obviously the model and view stuff is a separate layer, but in principle, those could be swapped too--it's all loosely coupled.) So the Django docs for templating are no good to you in that case. If you want to format a float in Jinja2, it looks like you need to use the format filter, according to the Jinja docs.
Without more info, I really can't say what's causing your ImportError, but floatformat is not going to work in a Jinja2 template, so maybe that has something to do with it.
I am setting up an application using Flask based on a tutorial I found on the web. The problem I am having is so far it seems like I will have to write a lot of code for each view/route that I want to make so I am trying to devise a better system but I think I dug myself into a hole where I wrote too much code before really testing each step and since im not familiar with the framework im kindof lost.
so what I want is a base view class that will extract away some boilerplate stuff. Here is my attempt so far.
import jinja2
from jinja2 import Environment as Jinja2Environment
from webassets import Environment as AssetsEnvironment
from webassets.loaders import YAMLLoader
from webassets.ext.jinja2 import AssetsExtension
from flask import render_template
from app import app
class BaseView(object):
def __init__(self):
"init"
def get_jinja_env(self):
jinja_env = Jinja2Environment(loader=jinja2.FileSystemLoader('templates/'), extensions=[AssetsExtension])
return jinja_env
def get_asset_env(self):
asset_loader = webassets.YAMLLoader('conf/assets.yml')
asset_env = asset_loader.load_environment()
bundles = asset_loader.load_bundles()
[asset_env.register(name, bundle) for name, bundle in bundles.iteritems()]
return asset_env
def render_tmpl(self, tmpl_file, **context):
"Renders Jinja Template"
jinja_env = self.get_jinja_env
jinja_env.assets_environment = self.get_asset_env
template = jinja_env.get_template(tmpl_file)
return template.render(context)
Class that attempts to inherit from BaseView
from app.BaseView import BaseView
from app import app
class HelloView(BaseView):
#app.route('/')
def respond(self):
self.render_tmpl('hello.html')
My reasoning behind this is later I intend to extend some Jinja functionality such as caching and have some data be available for every view and template.
You will want to use the View classes included in flask already.
As they are very well explained there is not much I could explain here. Just read through the docs and I think you will see, what you will have to do (the flask docs are awesome.)
If you want to cache you also might want to have a look at Flask-Cache.
This doesn't quite answer your question entirely, but I thought it was worth mentioning anyway.
You can 'export' variables into the Jinja environment globals:
app.jinja_env.globals['data'] = ['One', 'Two', 'Three']
Once you've done this, all templates have access to the data variable and can operate on it as if it were passed in via kargs. You don't really need to go to the trouble of creating a whole new view class; you can just process it once and then make it available everywhere. It's handy for sidebars and login statuses and whatnot.
In particular I want to use pystache but any guide for another template engine should be good enough to set it up.
If I understood correctly, I have to register the renderer factory in the __init__.py of my pyramid application.
config = Configurator(settings=settings)
config.add_renderer(None, 'pystache_renderer_factory')
Now I need to create the renderer factory and don't know how.
Even though I found the documentation about how to add a template engine, I didn't manage to set it up.
Finally I was able to add the pystache template engine following this guide:
https://groups.google.com/forum/#!searchin/pylons-discuss/add_renderer/pylons-discuss/Y4MoKwWKiUA/cyqldA-vHjkJ
What I did:
created the file mustacherenderer.py:
from pyramid.asset import abspath_from_asset_spec
import pystache
import os
def pystache_renderer_factory(info):
template = os.path.join(abspath_from_asset_spec('myproj:templates', False),
info.name)
f = open(template)
s = f.read()
f.close()
def _render(value, system):
return pystache.render(s, value)
return _render
added this to the __init__.py:
config.add_renderer('.pmt', 'myproj.mustacherenderer.pystache_renderer_factory')
working :)
add_renderer's second argument is supposed to be a class that implements the interface shown in "Adding a New Renderer". Pyramid will take pystache_renderer_factory and attempt to import it, so in your code the line import pystache_renderer_factory would have to work. This example won't ever resolve to a class, only a module or package, so you'll have to fix that first. It should be something like mypackage.pystache_renderer_factory.
The best way to learn how to write a renderer is probably to look at some that have been written already. Specifically the pyramid_jinja2 package, or in Pyramid's source there are very simple implementations of json and jsonp renderers. Notice how they all provide fairly unique ways to implement the required interface. Each factory accepts an info object, and returns a callable that accepts value and system objects.
https://github.com/Pylons/pyramid_jinja2/blob/master/pyramid_jinja2/init.py#L260
https://github.com/Pylons/pyramid/blob/master/pyramid/renderers.py#L135
Note that this answer works well until you create your Pyramid project with a scaffold. Once you do so, this related answer will prove more useful when constructing your Pystache/Mustache_Renderer_Factory: How to integrate pystache with pyramid?.