Hi everyone,

I used the bfg_alchemy paster template to create a default project  
with Traversal and SQLAlchemy. This gave me an initial insight on how  
to use traversal with an ORM and support URLs like 

In order to support something like:

  - http://example.com/tasks (all the tasks)
  - http://example.com/projects/{project_id}/tasks (all the tasks by  
  - http://example.com/projects/{project_id}/tasks/{task_id}

where projects/tasks are collections of resources and {projects_id}/ 
{task_id} represents one particular project resource, I came up with  
the following idea:

  - Create SQLAlchemy aware containers that expect a DBSession and  
"filter_by" keyword arguments.
  - Adapt the contained items when there are subordinate containers.

Of course I could just make a contained item (e.g. a project resource)  
traversable and avoid the adaption but I wanted to keep the individual  
resources unaware from the fact that the current application framework  
supports traversal (which I actually like a lot :-) ). Besides with  
adaption the subordinate contents of one resource may vary based on  
the parent container.

I am enclosing part of the code but you can download an experimental  
application from http://dl.getdropbox.com/u/260650/bfg_alchemy.zip  
(temporary location)

Do you think my approach makes sense or is it too complicated?



---------------------------------- example code  

class TraversableMapping(Contained):

     title = u''
     description = u''

     def __init__(self):
         self._contents = self._create_contents()
         for name in self._contents:
             locate(self._contents[name], self, name)

     def __getitem__(self, key):
         return self._contents[key]

     def get(self, key, default=None):
         return self._contents.get(key, default)

     def items(self):
         return self._contents.items()

     def iteritems(self):
         return self._contents.iteritems()

     def values(self):
         return self._contents.values()

     def itervalues(self):
         return self._contents.itervalues()

     def __len__(self):
         return len(self._contents)

     def _create_contents(self):
         raise NotImplementedError

class TraversableEntity(Contained):

     _entity = None

     def __init__(self, db_session, **filters):
         self.__db_session = db_session
         self.__filters = filters

     def __getitem__(self, key):
             key = int(key)
         except (ValueError, TypeError):
             raise KeyError(key)
         query = self._query.filter_by(id=key)
             item = query.one()
         except NoResultFound:
             raise KeyError(key)
             item = queryMultiAdapter((self, item), default=item)
             locate(item, self, key)
             return item

     def __len__(self):
         return self._query.count()

     def get(self, key, default=None):
             item = self.__getitem__(key)
         except KeyError:
             item = default
         return item

     def items(self):
         result = []
         for obj in self._query.all():
             locate(obj, self, obj.id)
             result.append((obj.id, obj))
         return result

     def iteritems(self):
         for obj in self._query:
             locate(obj, self, obj.id)
             yield (obj.id, obj)

     def values(self):
         result = []
         for obj in self._query.all():
             locate(obj, self, obj.id)
         return result

     def itervalues(self):
         for obj in self._query:
             locate(obj, self, obj.id)
             yield obj

     def _query(self):
         session = self.__db_session()
         query = session.query(self._entity)
         if len(self.__filters) > 0:
             query = query.filter_by(**self.__filters)
         return query

class TraversableProject(TraversableMapping):
     adapts(IProjectContainer, IProject)

     def __init__(self, parent, child):
         self._parent = parent
         self._child = child
         self.title = self._child.title
         self.description = self._child.description

     def __getattr__(self, name):
         return getattr(self._child, name)

     def _create_contents(self):
         return dict(tasks=TaskContainer(DBSession,  

class ProjectContainer(TraversableEntity):

     title = u'Projects'
     description = u'List of projects'
     _entity = Project

Repoze-dev mailing list

Reply via email to