Optio's [soaplib](http://trac.optio.webfactional.com/wiki/soaplib) makes it really straightforward to write SOAP web service views by using a decorator to specify types. Plus it's the only Python library, as of today, which is able to generate WSDL documents for your web service.
You can test it with a soaplib client:
>>> from soaplib.client import make_service_client
>>> from foo.views import HelloWorldService
>>> client = make_service_client('http://localhost:8000/hello_world/', HelloWorldService())
>>> client.say_hello('John', 2)
['Hello, John', 'Hello, John']
And get an WSDL document:
>>> client.server.wsdl('')
'<?xml version=\'1.0\' encoding=\'utf-8\' ?><definitions name="HelloWorldService"
...
</definitions>'
[A comment on a recent blog entry of mine](http://www.b-list.org/weblog/2008/feb/25/managers/#c63422) asked about a setup where one model has foreign keys pointing at it from several others, and how to write a manager which could attach to any of those models and query seamlessly on the relation regardless of what it's named.
This is a simple example of how to do it: in this case, both `Movie` and `Restaurant` have foreign keys to `Review`, albeit under different names. However, they both use `ReviewedObjectManager` to provide a method for querying objects whose review assigned a certain rating; this works because an instance of `ReviewedObjectManager` "knows" what model it's attached to, and can introspect that model, using [Django's model-introspection API](http://www.b-list.org/weblog/2007/nov/04/working-models/), to find out the correct name to use for the relation, and then use that to perform the query.
Using model introspection in this fashion is something of an advanced topic, but is extremely useful for writing flexible, reusable code.
**Also**, note that the introspection cannot be done in the manager's `__init__()` method -- at that point, `self.model` is still `None` (it won't be filled in with the correct model until a bit later) -- so it's necessary to come up with some way to defer the introspection. In this case, I'm doing it in a method that's called when the relation name is first needed, and which caches the result in an attribute.
- managers
- models
- introspection