Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] - نسخه متنی

David Ascher, Alex Martelli, Anna Ravenscroft

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


Recipe 14.14. Rendering Arbitrary Objects with Nevow


Credit: Valentino Volonghi, Matt Goodall


Problem


You're writing a web application that uses the
Twisted networking framework and the Nevow subsystem for web
rendering. You need to be able to render some arbitrary Python
objects to a web page.


Solution


Interfaces and adapters are the Twisted and Nevow approach to this
task. Here is a toy example web server script to show how they work:

from twisted.application import internet, service
from nevow import appserver, compy, inevow, loaders, rend
from nevow import tags as T
# Define some simple classes to be the example's "application data"
class Person(object):
def _ _init_ _(self, firstName, lastName, nickname):
self.firstName = firstName
self.lastName = lastName
self.nickname = nickname
class Bookmark(object):
def _ _init_ _(self, name, url):
self.name = name
self.url = url
# Adapter subclasses are the right way to
join application data to the web:
class PersonView(compy.Adapter):
"" Render a full view of a Person. ""
_ _implements_ _ = inevow.IRenderer
attrs = 'firstName', 'lastName', 'nickname'
def rend(self, data):
return T.div(_class="View person") [
T.p['Person'],
T.dl[ [(T.dt[attr], T.dd[getattr(self.original, attr)])
for attr in self.attrs]
]
]
class BookmarkView(compy.Adapter):
"" Render a full view of a Bookmark. ""
_ _implements_ _ = inevow.IRenderer
attrs = 'name', 'url'
def rend(self, data):
return T.div(_class="View bookmark") [
T.p['Bookmark'],
T.dl[ [(T.dt[attr], T.dd[getattr(self.original, attr)])
for attr in self.attrs]
]
]
# register the rendering adapters (could be done from a config textfile)
compy.registerAdapter(PersonView, Person, inevow.IRenderer)
compy.registerAdapter(BookmarkView, Bookmark, inevow.IRenderer)
# some example data instances for the 'application'
objs = [
Person('Valentino', 'Volonghi', 'dialtone'),
Person('Matt', 'Goodall', 'mg'),
Bookmark('Nevow', 'http://www.nevow.com'),
Person('Alex', 'Martelli', 'aleax'),
Bookmark('Alex', 'http://www.aleax.it/'),
Bookmark('Twisted', 'http://twistedmatrix.com/'),
Bookmark('Python', 'http://www.python.org'),
]
# a simple Page that renders a list of objects
class Page(rend.Page):
def render_item(self, ctx, data):
return inevow.IRenderer(data)
docFactory = loaders.stan(
Tl[
T.body[
T.ul(data=objs, render=rend.sequence)[
T.li(pattern='item')[render_item],
],
],
]
)
# start this very-special-purpose tiny toy webserver:
application = service.Application('irenderer')
httpd = internet.TCPServer(8000, appserver.NevowSite(Page( )))
httpd.setServiceParent(application)


Discussion


This recipe's purpose is to provide an example of
how to get Nevow to render instances of application classes directly
to a web page. To supply this example, the recipe shows two classes,
Person and Bookmark, whose instances contain information which, one
can suppose, is coming from a database, or from a file, or from some
other site on the web, wherever.

A key point is that the application classes do not get altered in any
way to allow their instances to be rendered onto web pages: rather,
adaptation is used to allow instances of such
classes to be rendered through separate renderer-adapter classes.

We need two different adapters, one each for Person
and Bookmark. We code the two adapters as classes
PersonView and BookmarkView, each
inheriting from compy.Adapter and overriding the
rend method.

compy.Adapter is an abstract superclass intended
just for this purpose: it accepts as its constructor argument an
object that must be adapted to another interface, and holds that
object as self.original for its
subclasses' benefit. Each subclass asserts that it
implements inevow.IRenderer by listing that
interface in its class-level _ _implements_ _
attribute.

inevow.IRenderer is an interface that supplies a
rend method. The Nevow rendering pipeline knows
about IRenderer and calls the
rend method of the interface to serialize objects
to HTML. Objects that implement the interface (on their own behalf or
as adapters of other objects) can directly become part of the
rendering pipeline.

The two key statements of this recipe are the two calls to the
registerAdapter function of
Nevow's module compy:

compy.registerAdapter(PersonView, Person, inevow.IRenderer)
compy.registerAdapter(BookmarkView, Bookmark, inevow.IRenderer)

These calls tell Nevow that PersonView is the class
to use to adapt any instance of Person to interface
IRenderer, and similarly for
BookmarkView and Bookmark. So, when
the IRenderer interface is called with an instance
p of Person as its
argument, it automatically returns an adapter that is an instance of
PersonView with p as its
self.original (and, again, similarly for
Bookmark).

Note how accurately this approach distributes appropriate knowledge
to the various parts of the software and minimizes coupling among
them while strengthening cohesion within each. Nevow itself has no
built-in knowledge of any application class nor of any specific
adapter: nor does it need any such knowledge. Nevow just specifies
the IRenderer interface it needs for rendering and
the registerAdapter function used to inform the
framework about adaptation connections. Application-level classes
neither have nor need any knowledge of the framework at all. Each
adapter class knows about the application level class
it's adapting, the interface it's
implementing, and utilities such as the Adapter
base class that the framework supplies (just to factor out a little
repetitive coding that would be needed otherwise), and the
tags mechanism. (The tags mechanism eases dynamic
generation of HTML output. However, you could code adapters to return
strings with HTML markup directly, if that suited the needs of your
specific application better than the tags
mechanism does.)

Finally, the recipe includes an example Page class
which ties everything togetheragain, for convenience, using
tags to generate the output. Page
uses (explicitly) the rend.sequence renderer
provided by Nevow to loop over a sequence and render each item, and
(implicitly) the various adapters, by
"casting" each item to the
IRenderer interface. The recipe ends with three
lines to build Twisted application and service objects and to put
them together, so that running this recipe's script
with Twisted's twistd
general-purpose daemon provides a small demonstration one-page web
site running on the local host at port 8000.

A more complete (and complicated) version of this recipe can be found
as part of the Nevow 0.3 distribution, downloadable from http://www.nevow.com, as
examples/irenderer.tac.


See Also


Nevow is at http://www.nevow.com;
Twisted is at http://twistedmatrix.com/.

/ 394