惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fox-IT International blog
Recent Announcements
Recent Announcements
D
Docker
IT之家
IT之家
B
Blog
Jina AI
Jina AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
量子位
C
Check Point Blog
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
博客园 - 司徒正美
李成银的技术随笔
美团技术团队
Blog — PlanetScale
Blog — PlanetScale
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
T
The Blog of Author Tim Ferriss
酷 壳 – CoolShell
酷 壳 – CoolShell
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
L
LangChain Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
Visual Studio Blog
T
Tailwind CSS Blog
H
Help Net Security
Engineering at Meta
Engineering at Meta
小众软件
小众软件
B
Blog RSS Feed
Stack Overflow Blog
Stack Overflow Blog
月光博客
月光博客
M
Microsoft Research Blog - Microsoft Research
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Last Week in AI
Last Week in AI
Martin Fowler
Martin Fowler
Stack Overflow Blog
Stack Overflow Blog

Secret Weblog

Becoming More Xee: A Modern XPath and XSLT Engine in Rust Looking for new challenges! Repeat Yourself, A Bit The Curious Case of Quentell The Humble For Loop in Rust The Humble For Loop in JavaScript Don't Look Down on Print Debugging Question Best Practices I Was a 1980s Teenage Programmer Part 5: Achieving Assembly I Was a 1980s Teenage Programmer Part 4: The Call of Assembly The Tooling Shift I Was a 1980s Teenage Programmer Part 3: MSX-2 JavaScript: when you need two ways to do it! Empowering Programming Languages Bloat and Retrofuturism Refreshing my Blog Again Random Rust Impressions Apilar: An Alife System I Was a 1980s Teenage Programmer Part 2: Olivetti M24 I Was a 1980s Teenage Programmer: the Alphatronic SolidJS fits my brain Is premature optimization the root of all evil? Framework Patterns: JavaScript edition Roll Your Own Frameworks Looking for new challenges Framework Patterns Secret Weblog Highlights Refactoring to Multiple Exit Points mstform: a form library for mobx-state-tree Seven Years: A Very Personal History of the Web Looking for new challenges Morepath 0.16 released! Is Morepath Fast Yet? Introducing Bob Strongpinion Punctuated Equilibrium in Software Morepath 0.15 released! Impressions of React Europe 2016 Morepath 0.14 released! Morepath 0.13 now with Dectate Dectate: advanced configuration for Python code JavaScript Dependencies Revisited: An Example Project The Incredible Drifting Cyber A Brief History of Reselect The Emerging GraphQL Python stack Thoughts about React Europe Build a better batching UI with Morepath and Jinja2 GraphQL and REST 10 reasons to check out the Morepath web framework in 2015 A Review of the Web and how Morepath fits in Morepath 0.9 released! Better REST with Morepath 0.8 Morepath 0.7: new inter-app linking They say something I don't like so they must be lying! Life at the Boundaries: Conversion and Validation BowerStatic 0.4 released! Morepath 0.6 released! Morepath 0.5(.1) and friends released! New HTTP 1.1 RFCs versus WSGI Against On Naming In Open Source My visit to EuroPython 2014 Morepath 0.4.1 released (with Python 3 fixes) Morepath 0.4 and breaking changes Announcing BowerStatic Morepath 0.3 released! Morepath 0.2 Morepath Python 3 support The Call of Python 2.8 Morepath 0.1 released! WebOb and Werkzeug compared Morepath: from Werkzeug to WebOb Racing the Morepath: SQLAlchemy Integration The Centre Cannot Hold Breaking Morepath Changes Morepath Update How to do REST with Morepath Morepath Security the Gravity of Python 2 #python2.8 discussion channel on freenode Alex Gaynor on Python 3 Morepath Documentation Starting to Take Shape Back to the Center Morepath App Reuse Implementing Grok Grok: the Idea Why Linux Works for Me On the Morepath Reg, Now With More Generic! The New Zope as a Web Framework Jim Fulton, Zope Architect Renewing Zope Object Publishing The Weirdness of Zope The Rise of Zope My Exit from Zope Reg: Component Architecture Reimagined JSConf EU 2013 impressions Obviel 1.0! JS Dependency Tools Redux
Server Templating in Morepath 0.10
Martijn Faassen · 2015-04-09 · via Secret Weblog

Introduction

I just released Morepath 0.10 (CHANGES)! Morepath is a modern Python web framework that combines power with simplicity of use. Morepath 0.10's biggest new feature is server-side templating support.

Most Python web frameworks were born at a time when server-side templating was the only way to get HTML content into a web browser. Templates in the browser did not yet exist. Server templating was a necessity for a server web framework, built-in from day 1.

The web has changed and much more can be done in the browser now: if you want a web page, you can accomplish it with client-side JavaScript code, helped by templates, or embedded HTML-like snippets in JavaScript, like what the React framework does. Morepath is a web framework that was born in this new era.

Morepath could take a more leisurely approach to server templating. We recommend that users rely on client-side technology to construct a UI -- something that Morepath is very good at supporting. For many web applications, this approach is fine and leads to more responsive user interfaces. It also has the benefit that it supports a strong separation between user interface and underlying data. And you could still use server template engines with Morepath, but with no help from the framework.

But there is still room for server templates. Server-generated HTML has its advantages. It's the easiest way to create a bookmarkable traditional web site -- no client-side routing needed. For more dynamic web applications it can also sometimes make sense to send a server-rendered HTML page to the client as a starting point, and only switch to a client-side dynamic code later. This is useful in those cases where you want the end-user to see a web page as quickly as possible: in that case sending HTML directly from the server can still be faster, as there is no need for the browser to load and process JavaScript in order to display some content.

So now Morepath has now, at last, gained server template support, in version 0.10. We took our time. We prototyped a bit first. We worked out the details of the rest of the framework. As we will see, it's nice we had the chance to spend time on other aspects of Morepath first, as that infrastructure now also makes template language integration very clean.

The basics

Say you want to use Jinja2, the template language used by Flask, in Morepath. Morepath does not ship with Jinja2 or any other template language by default. Instead you can install it as a plugin in your own project. The first thing you do is modify your project's setup.py and add more.jinja2 to install_requires:

install_requires=[
  'more.jinja2',
],

Now when you install your project's dependencies, it pulls in more.jinja2, which also pulls in the Jinja2 template engine itself.

Morepath's extension system works through subclassing. If you want Jinja2 support in your Morepath application, you need to subclass your Morepath app from the Jinja2App:

from more.jinja2 import Jinja2App

class App(Jinja2App):
    pass

The App class is now aware of Jinja2 templates.

Next you need to tell your app what directory to look in for templates:

@App.template_directory()
def get_template_directory():
    return 'templates'

This tells your app to look in the templates directory next to the Python module you wrote this code in, so the templates subdirectory of the Python package that contains your code.

Now you can use templates in your code. Here's a HTML view with a template:

@App.html(model=Customer, template='customer.jinja2')
def customer_default(self, request):
    return {
      'name': self.name,
      'street': self.street,
      'city': self.city,
      'zip': self.zip_code
    }

The view returns a dictionary. This dictionary contains the variables that should go into the customer.jinja2 template, which should be in the templates directory. Note that you have to use the jinja2 extension, as Morepath recognizes how to interpret a template by its extension.

You can now write the customer.jinja2 template that uses this information:

<html>
<body>
  <p>Customer {{name}} lives on {{street}} in {{city}}.</p>
  <p>The zip code is {{zip}}.</p>
</body>
</html>

You can use the usual Jinja2 constructs here.

When you access the view above, the template gets rendered.

Chameleon

What if you want to use Chameleon (ZPT) templates instead of Jinja2 templates? We've provided more.chameleon that has this integration. Include it in install_requires in setup.py, and then do this to integrate it into your app:

from more.chameleon import ChameleonApp

class App(ChameleonApp):
    pass

You can now set up a template directory and put in .pt files, which you can then refer to from the template argument to views.

You could even subclass both ChameleonApp and Jinja2App apps and have an application that uses both Chameleon and Jinja2 templates. While that doesn't seem like a great idea, Morepath does allow multiple applications to be composed into a larger application, so it is nice that it is possible to combine an application that uses Jinja2 with another one that uses Chameleon.

Overrides

Imagine there is an application developed by a third party that has a whole bunch of templates in them. Now without changing that application directory you want to override a template in it. Perhaps you want to override a master template that sets up a common look and feel, for instance.

In Morepath, template overrides can be done by subclassing the application (just like you can override anything else):

class SubApp(App):
    pass

@SubApp.template_directory()
def get_template_directory_override():
    return 'override_templates'

That template_directory directive tells SubApp to look for templates in override_templates first before it checks the templates directory that was set up by App.

If we want to override master.jinja2, all we have to do is copy it from templates into override_templates and change it to suit our purposes. Since a template with that name is found in override_templates first, it is found instead of the one in templates. The original App remains unaffected.

Implementation

In the introduction we mentioned that the template language integration code into Morepath is clean. You should be able to integrate other template engines easily too. Here is the code that integrates Jinja2 into Morepath:

import os
import morepath
import jinja2


class Jinja2App(morepath.App):
    pass


@Jinja2App.setting_section(section='jinja2')
def get_setting_section():
    return {
        'auto_reload': False,
    }


@Jinja2App.template_loader(extension='.jinja2')
def get_jinja2_loader(template_directories, settings):
    config = settings.jinja2.__dict__.copy()

    # we always want to use autoescape as this is about
    # HTML templating
    config.update({
        'autoescape': True,
        'extensions': ['jinja2.ext.autoescape']
    })

    return jinja2.Environment(
      loader=jinja2.FileSystemLoader(template_directories),
      **config)


@Jinja2App.template_render(extension='.jinja2')
def get_jinja2_render(loader, name, original_render):
    template = loader.get_template(name)

    def render(content, request):
        variables = {'request': request}
        variables.update(content)
        return original_render(template.render(**variables), request)
    return render

The template_loader directive sets up an object that knows how to load templates from a given list of template directories. In the case of Jinja2 that is the Jinja2 environment object.

The template_render directive then tells Morepath how to render individual templates: get them from the loader first, and then construct a function that given content returned by the view function and request, uses the template to render it.

Documentation

For more documentation, see the Morepath documentation on templates.

Let us know what you think!