Follow us

Pyramid traversal: wrap your model with a resource adapter

Saturday 10 March 2012

If you use the python-based Pyramid web application framework, and would like traversal flavoured view lookup, but want clean model classes, this might be the way to go.
Traversal traverses a tree of so-called resources, which often correspond to your models. For example, if you are working on an email client, you may have an Email model, which might be saved in the email table of your database, have a sender and subject property, and a send method.

class Email(object):

	def __init__(self, subject, from, to, content):
		self.subject = subject

	def subject():
		return self.subject

	def send(self):
		#send email
Then if you want to display Emails in your web application, you need some class that acts as an email resource for traversal. A resource must implement the __name__ and __parent__ properties, and often has a __getitem__ and __iter__ method to traverse down to its children.

From a software architectural viewpoint, these properties and methods together form the Resource interface. This interface is part of your application’s infrastructure layer, or, to put it in Domain Driven Design terminology, they are not a part of the domain model.
To come back to the example, your Email may appear elsewhere in your application, for instance when called from another API, such as a command-line interface or desktop GUI. It then wouldn’t need the Resource interface. Besides, it would complicate your domain model.

So the object-oriented solution is to separate these two responsibilities: the core Model class, and the class that implements the Resource interface for that model. The most straightforward way to do is with the adapter pattern. (here is an excellent blogpost about the adapter pattern for python) For each model FooModel, create a class FooResource, which implements the Resource interface, and wraps the model object.
class EmailResource(object):

	def __init__(self, email, parent):
		self.__name__ = email.subject
		self.__parent__ = parent
		self.inner = email

	def __getitem__(self, key):
		if key == ‘replies’:
			#use your email to somehow retrieve all replies to it, e.g.
			return EmailListResource(emailRepository.getRepliesFor(self.inner))
		else:
			raise KeyError

	@property
	def subject(self):
		return self.inner.subject

	def send(self):
		self.inner.send()
The Resource adapter fulfills the Resource interface, offering name, parent, and a getitem method to get to a child on the traversal tree. It delegates these to the inner model object. It also implements the regular model interface, meaning that your can use the traversal-retrieved object in your application as if it were a regular ‘Email’. It simply delegates this behavior to the inner object as well.

From this point, it will also be easier to standardize your resources into, say, a ListResource, a SearchableResource, you name it.

Comments? Write me an email or discuss on facebook, google+ or twitter.

Read other blog posts