[Twisted-Python] Dynamic web application using twisted.web.resource

Donovan Preston dp at twistedmatrix.com
Tue Jul 30 15:15:13 EDT 2002


On Tuesday, July 30, 2002, at 09:19 AM, Mukhsein Johari wrote:
>
> The project:
> I would like to serve a dynamic website using the twisted web server. I
> understand that the webserver's 'root' directory can be set at a file? 
> I may
> have a misunderstanding of the code and docs but if so, feel free to 
> set me
> straight.

When you create a tap file using "bin/mktap web --path /foo/bar/baz", 
mktap creates a File instance, which is a Resource subclass, which knows 
to look in "/foo/bar/baz" as the root directory of the site. However, 
mktap is just a "helper" script that instanciates, configures, and 
persists various common application types. If you want the root object 
of your web site to be a custom Resource subclass that only serves 
dynamic pages, you're free to do that.

> The website (not real):
> http://www.mywebsite.com/
>
> This is the root of the site, which is in reality a erm..rpy? program? 
> Which
> means that there are _no_ static pages at all. And no other 'file' -
> everything goes through that .rpy file. (or whatever else I should be 
> using)

So, as I just said, what you should do is create your own Application 
instance, create an instance of twisted.web.server.Site, and create your 
own custom Resource subclass to act as the root of that site. Your 
Resource subclass should override getChild(name, request) and 
render(request), as I will describe below. Here's how you would go about 
starting your custom server:

# MyCoolWebServer.py

from twisted.web import server
from twisted.internet import reactor

import myGreatResourceSubclass

root = myGreatResourceSubclass.MyRoot()

site = server.Site(root)

reactor.listenTCP(8080, site)
reactor.run()

> In a browser, entering this would get a dynamically 'constructed' page 
> which
> is in fact:
>
> myobject.index()

In the example above, visiting the root page would end up invoking 
root.render(request).

> From here on, something like:
> http://www.mywebsite.com/projects/project_ako
>
> would actually be (in the code) something like:
>
> myobject.projects["project_ako"].index(myvar=None)

If these semantics are what you *really* want (i.e. transparency, 
getitem, or getattr being used for traversal), I suggest looking at Zope 
or Quixote, as Itamar suggested. However, here's how the following would 
look in twisted:

root.getChild("projects", request).getChild("project_ako", 
request).render(request)

In your root Resource subclass, you can define getChild to do whatever 
you wish such as dynamically generate a new Resource subclass to handle 
the "projects" portion, which in turn has a getChild that knows how to 
create an object to handle the "project_ako" portion, which in turn has 
a render() method that returns a string, which will be sent to the 
browser.

> which returns an html page suitable for the browser's consumption.
> On the other hand this:
>
> http://www.mywebsite.com/projects/project_ako?myvar=bold
>
> (for http GET. POST should be handled as well...how? I am guessing the 
> request
> object?)
>
> Would call:
> myobject.projects["project_ako"].index(myvar='bold')

It would be exactly the same call as above, except request.args would be 
a dictionary that looked like this:

{'myvar': ['bold']}

Note that every value in the args dictionary is always a list, to make 
handling lists and non lists more uniform.

> Any other subobject of project_ako would 'call' a method on that object.
>
> So for:
> http://www.mywebsite.com/projects/project_ako/getSize
>
> Would call:
> myobject.projects["project_ako"].getSize()
>
> The return value being sent back to the browser. Calls to non-existing 
> methods
> get a "No such method or object" error returned - formatted, of course.

If you want automatic getChild traversal to stop at the object 
representing "project_ako", set isLeaf = 1 on the object representing 
"project_ako". This will cause render(request) to be called on 
"project_ako" with the remaining elements of the path in 
request.postpath. You can then implement the semantics described above 
in your render() method.

However, I find it much easier to divide functionality into separate 
classes and always use render() to do the html generation.

> The question is of course, how do you differentiate between an object 
> and a
> method? This is done by the application itself. It would check to see 
> if that
> object has a method with that name, if not check to see if it has a 
> child
> object with that name. Else return error.

If this is *really* the functionality that you want, again, this is far 
more similar to the traversal semantics of Zope or Quixote. Twisted has 
taken a far more explicit tack, where there is a specific api that your 
objects must implement to provide object-publishing functionality.

>
> The thing is, I know I need to use twisted.web.resource but I'm not sure
> _how_. How does this fit in with the .rpy file? I think I need to 
> create my
> modules and classes and then create an .rpy which acts as the
> erm..'interface' to the modules and classes. Could someone give me some 
> hints
> and tips?
>
> Conceptually, it's quite simple but I can't seem to figure out how to 
> do it
> with twisted...Anyway, thanks for any help, in advance.

Hope this helps!

Donovan





More information about the Twisted-Python mailing list