tutorial jinja get_template async africa python-2.7 frameworks jinja2 cherrypy

python-2.7 - async - jinja2 get_template



Comenzando con Cherrypy y Jinja2 (2)

Esta es la primera vez que profundizo en el desarrollo web en Python. Mi única otra experiencia es PHP, y nunca usé un framework antes, así que estoy encontrando esto muy intimidante y confuso.

Estoy interesado en aprender CherryPy / Jinja2 para hacer un monitor ZFS para mi NAS. He leído los fundamentos de los documentos sobre CherryPy / Jinja2 pero me parece que las muestras son inconexas y demasiado simplistas, realmente no entiendo cómo hacer que estas 2 cosas "se unan" con gracia.

Algunas preguntas que tengo:

  1. ¿Hay algún tutorial simple que demuestre cómo logras que CherryPy y Jinja2 funcionen juntos muy bien? Estoy encontrando muestras que son demasiado simples, como las muestras en los documentos CherryPy / Jinja2, o de manera compleja. (ejemplo: https://github.com/jovanbrakus/cherrypy-example ).

  2. ¿Existe una forma estandarizada o "esperada" para crear aplicaciones web para CherryPy? (Ejemplo: ¿Cómo debería ser la estructura de mi directorio? ¿Hay alguna manera de declarar cosas estáticas, incluso es necesario?)

  3. ¿Alguien ha recomendado literatura para esto o la documentación en línea es el mejor recurso?


Felicitaciones por elegir Python, estoy seguro de que aprenderás a amarlo como yo.

Con respecto a CherryPy, no soy un experto, pero también estuve en el mismo barco que tú hace unos días y estoy de acuerdo en que los tutoriales están un poco dislocados por partes.

Para integrar Jinja2, como en su página de documento , el fragmento de HTML debería haber especificado que es el archivo de plantilla y, como tal, guardado en la ruta /templates/index.html. También usaron variables que no coincidían en la muestra del código de la plantilla y la muestra del controlador.

El siguiente es, en cambio, una muestra completa de trabajo de un mundo hello simple utilizando CherryPy y Jinja2

/main.py:

import cherrypy from jinja2 import Environment, FileSystemLoader env = Environment(loader=FileSystemLoader(''templates'')) class Root: @cherrypy.expose def index(self): tmpl = env.get_template(''index.html'') return tmpl.render(salutation=''Hello'', target=''World'') cherrypy.config.update({''server.socket_host'': ''127.0.0.1'', ''server.socket_port'': 8080, }) cherrypy.quickstart(Root())

/templates/index.html:

<h1>{{ salutation }} {{ target }}</h1>

Luego, en el intérprete de comandos / shell, preséntela usando:

python main.py

Y en su navegador debería poder verlo en http://localhost:8080

Es de esperar que te ayude a conectar plantillas Jinja2 a tu aplicación CherryPy. CherryPy es realmente un marco ligero y muy flexible, donde puedes elegir diferentes formas de estructurar tu código y estructuras de archivos.


Estructura de la aplicación

Primero sobre la estructura de directorio estándar de un proyecto. No hay ninguno, ya que CherryPy no lo ordena, ni le dice qué capa de datos, validación de formulario o motor de plantilla usar. Todo depende de usted y sus requisitos. Y, por supuesto, esta es una gran flexibilidad, ya que causa cierta confusión a los principiantes. Así es como se ve una estructura de directorio de aplicación cercana a la palabra real.

. — Python virtual environment └── website — cherryd to add this to sys.path, -P switch ├── application │ ├── controller.py — request routing, model use │ ├── model.py — data access, domain logic │ ├── view — template │ │ ├── layout │ │ ├── page │ │ └── part │ └── __init__.py — application bootstrap ├── public │ └── resource — static │ ├── css │ ├── image │ └── js ├── config.py — configuration, environments └── serve.py — bootstrap call, cherryd to import this, -i switch

Luego, pararte en la raíz del entorno virtual , generalmente haces lo siguiente para iniciar CherryPy en el entorno de desarrollo. cherryd es la manera sugerida por CherryPy de ejecutar una aplicación.

. bin/activate cherryd -i serve -P website

Templating

Ahora veamos más de cerca el directorio de plantillas y cómo puede verse.

. ├── layout │ └── main.html ├── page │ ├── index │ │ └── index.html │ ├── news │ │ ├── list.html │ │ └── show.html │ ├── user │ │ └── profile.html │ └── error.html └── part └── menu.html

Para aprovechar la característica de Jinja2 de la herencia de plantillas , aquí hay diseños que definen la estructura de una página, los espacios que se pueden llenar en una página en particular. Puede tener el diseño de un sitio web y el diseño de las notificaciones por correo electrónico. También hay un directorio para una parte, fragmento reutilizable utilizado en diferentes páginas. Ahora veamos el código que corresponde a la estructura de arriba.

También he hecho que lo siguiente esté disponible como un ejecutable que es más fácil de navegar por los archivos, puede ejecutarlo y jugar con él. Los caminos comienzan con . como en el árbol de la primera sección.

sitio web / config.py

# -*- coding: utf-8 -*- import os path = os.path.abspath(os.path.dirname(__file__)) config = { ''global'' : { ''server.socket_host'' : ''127.0.0.1'', ''server.socket_port'' : 8080, ''server.thread_pool'' : 8, ''engine.autoreload.on'' : False, ''tools.trailing_slash.on'' : False }, ''/resource'' : { ''tools.staticdir.on'' : True, ''tools.staticdir.dir'' : os.path.join(path, ''public'', ''resource'') } }

sitio web / serve.py

#!/usr/bin/env python # -*- coding: utf-8 -*- from application import bootstrap bootstrap() # debugging purpose, e.g. run with PyDev debugger if __name__ == ''__main__'': import cherrypy cherrypy.engine.signals.subscribe() cherrypy.engine.start() cherrypy.engine.block()

sitio web / aplicación / __ init__.py

La parte notable aquí es una herramienta CherryPy que ayuda a evitar la repetición de plantillas relacionadas. Solo necesita devolver un dict del manejador de página CherryPy con datos para la plantilla. Siguiendo el principio de convención sobre configuración, la herramienta cuando no se proporciona el nombre de la plantilla usará classname/methodname.html por ejemplo, user/profile.html . Para anular la plantilla predeterminada, puede usar @cherrypy.tools.template(name = ''other/name'') . También tenga en cuenta que la herramienta expone un método de forma automática, por lo que no es necesario agregar @cherrypy.expose en la parte superior

# -*- coding: utf-8 -*- import os import types import cherrypy import jinja2 import config class TemplateTool(cherrypy.Tool): _engine = None ''''''Jinja environment instance'''''' def __init__(self): viewLoader = jinja2.FileSystemLoader(os.path.join(config.path, ''application'', ''view'')) self._engine = jinja2.Environment(loader = viewLoader) cherrypy.Tool.__init__(self, ''before_handler'', self.render) def __call__(self, *args, **kwargs): if args and isinstance(args[0], (types.FunctionType, types.MethodType)): # @template args[0].exposed = True return cherrypy.Tool.__call__(self, **kwargs)(args[0]) else: # @template() def wrap(f): f.exposed = True return cherrypy.Tool.__call__(self, *args, **kwargs)(f) return wrap def render(self, name = None): cherrypy.request.config[''template''] = name handler = cherrypy.serving.request.handler def wrap(*args, **kwargs): return self._render(handler, *args, **kwargs) cherrypy.serving.request.handler = wrap def _render(self, handler, *args, **kwargs): template = cherrypy.request.config[''template''] if not template: parts = [] if hasattr(handler.callable, ''__self__''): parts.append(handler.callable.__self__.__class__.__name__.lower()) if hasattr(handler.callable, ''__name__''): parts.append(handler.callable.__name__.lower()) template = ''/''.join(parts) data = handler(*args, **kwargs) or {} renderer = self._engine.get_template(''page/{0}.html''.format(template)) return renderer.render(**data) if template and isinstance(data, dict) else data def bootstrap(): cherrypy.tools.template = TemplateTool() cherrypy.config.update(config.config) import controller cherrypy.config.update({''error_page.default'': controller.errorPage}) cherrypy.tree.mount(controller.Index(), ''/'', config.config)

sitio web / aplicación / controller.py

Como puede ver con el uso de la herramienta, los manejadores de páginas parecen bastante limpios y serán consistentes con otras herramientas, por ejemplo, json_out .

# -*- coding: utf-8 -*- import datetime import cherrypy class Index: news = None user = None def __init__(self): self.news = News() self.user = User() @cherrypy.tools.template def index(self): pass @cherrypy.expose def broken(self): raise RuntimeError(''Pretend something has broken'') class User: @cherrypy.tools.template def profile(self): pass class News: _list = [ {''id'': 0, ''date'': datetime.datetime(2014, 11, 16), ''title'': ''Bar'', ''text'': ''Lorem ipsum''}, {''id'': 1, ''date'': datetime.datetime(2014, 11, 17), ''title'': ''Foo'', ''text'': ''Ipsum lorem''} ] @cherrypy.tools.template def list(self): return {''list'': self._list} @cherrypy.tools.template def show(self, id): return {''item'': self._list[int(id)]} def errorPage(status, message, **kwargs): return cherrypy.tools.template._engine.get_template(''page/error.html'').render()

En esta aplicación de demostración utilicé el archivo blueprint css, para demostrar cómo funciona el manejo de recursos estáticos. Ponlo en el website/application/public/resource/css/blueprint.css . El resto es menos interesante, solo las plantillas Jinja2 para completar.

sitio web / application / view / layout / main.html

<!DOCTYPE html> <html> <head> <meta http-equiv=''content-type'' content=''text/html; charset=utf-8'' /> <title>CherryPy Application Demo</title> <link rel=''stylesheet'' media=''screen'' href=''/resource/css/blueprint.css'' /> </head> <body> <div class=''container''> <div class=''header span-24''> {% include ''part/menu.html'' %} </div> <div class=''span-24''>{% block content %}{% endblock %}</div> </div> </body> </html>

sitio web / application / view / page / index / index.html

{% extends ''layout/main.html'' %} {% block content %} <div class=''span-18 last''> <p>Root page</p> </div> {% endblock %}

sitio web / aplicación / vista / página / noticias / lista.html

{% extends ''layout/main.html'' %} {% block content %} <div class=''span-20 last prepend-top''> <h1>News</h1> <ul> {% for item in list %} <li><a href=''/news/show/{{ item.id }}''>{{ item.title }}</a> ({{ item.date }})</li> {% endfor %} </ul> </div> {% endblock %}

sitio web / aplicación / vista / página / noticias / show.html

{% extends ''layout/main.html'' %} {% block content %} <div class=''span-20 last prepend-top''> <h2>{{ item.title }}</h2> <div class=''span-5 last''>{{ item.date }}</div> <div class=''span-19 last''>{{ item.text }}</div> </div> {% endblock %}

sitio web / aplicación / vista / página / usuario / perfil.html

{% extends ''layout/main.html'' %} {% block content %} <div class=''span-18''> <table> <tr><td>First name:</td><td>John</td></tr> <tr><td>Last name:</td><td>Doe</td></tr> <table> </div> {% endblock %}

sitio web / aplicación / vista / página / error.html

Es una página de 404.

{% extends ''layout/main.html'' %} {% block content %} <h1>Error has happened</h1> {% endblock %}

sitio web / application / view / part / menu.html

<div class=''span-4 prepend-top''> <h2><a href=''/''>Website</a></h2> </div> <div class=''span-20 prepend-top last''> <ul> <li><a href=''/news/list''>News</a></li> <li><a href=''/user/profile''>Profile</a></li> <li><a href=''/broken''>Broken</a></li> </ul> </div>

Referencias

El código anterior se relaciona estrechamente con la sección de backend de qooxdoo-website-skeleton . Para el despliegue completo de Debain de tal aplicación, el esqueleto de cereza-webapp puede ser útil.