Welcome, guest | Sign In | My Account | Store | Cart

Notice! PyPM is being replaced with the ActiveState Platform, which enhances PyPM’s build and deploy capabilities. Create your free Platform account to download ActivePython or customize Python with the packages you require and get automatic updates.


horae.layout is unavailable in PyPM, because there aren't any builds for it in the package repositories. Click the linked icons to find out why.

 Python 2.7Python 3.2Python 3.3
Windows (32-bit)
Windows (64-bit)
Mac OS X (10.5+)
Linux (32-bit)
Linux (64-bit)


The horae.layout package provides the global layout for the Horae resource planning system by defining base classes for views, forms (add, edit, delete and display) and viewlets. Additionally the following features are provided:

  • Registration of several viewlet managers
  • Integration of megrok.navigation
  • Helper view to create tables
  • Generic views for listing, adding, editing and deleting objects in a container
  • Possibility to register fanstatic resources

System Message: WARNING/2 (<string>, line 13)

Bullet list ends without a blank line; unexpected unindent.

through named adapters * Registration of the horae.datetime widgets * Registration of rich text widgets using megrok.form



The aforementioned base classes for views, forms and viewlets are defined in horae.layout.layout. All the views defined there provide the functionality to be called with two special parameters provided through GET or POST:

plain If this parameter is set to any truth value only the views result is rendered without the whole layout put around. selector If this parameter is set to any CSS selector only the contents of the element matching the selector is returned.

Those base classes are also responsible for including the fanstatic resources provided by the named adapters implementing horae.layout.interfaces.IResourceProvider.

Add forms

Creating an add form using horae.layout is done by sub-classing from the provided base class horae.layout.layout.AddForm and implementing the required methods:

System Message: WARNING/2 (<string>, line 45)

Literal block expected; none found.

import grok

from horae.layout import layout from some.module.interfaces import ISampleContent, ISampleContainer from some.module.content import SampleContent

class AddSampleContent(layout.AddForm): grok.context(ISampleContainer) form_fields = grok.AutoFields(ISampleContent)

def create(self, **data): return SampleContent()

System Message: WARNING/2 (<string>, line 55); backlink

Inline strong start-string without end-string.

def add(self, obj): self.context[obj]

This will render a form having a Add and Cancel button.

Edit forms

Edit forms work pretty much the same as add forms. The only difference is the class to be sub-classed and that there are no methods required to be implemented:

System Message: WARNING/2 (<string>, line 69)

Literal block expected; none found.

class EditSampleContent(layout.EditForm): grok.context(ISampleContent) form_fields = grok.AutoFields(ISampleContent)

This will render a form having a Save changes and Cancel button.

Display forms

Like edit forms display forms require no implementation at all:

System Message: WARNING/2 (<string>, line 80)

Literal block expected; none found.

class DisplaySampleContent(layout.DisplayForm): grok.context(ISampleContent) form_fields = grok.AutoFields(ISampleContent)

Delete forms

Delete forms provide a confirmation view before actually deleting an object and are implemented by sub-classing from horae.layout.layout.DeleteForm:

System Message: WARNING/2 (<string>, line 90)

Literal block expected; none found.

class DeleteSampleContent(layout.DeleteForm): grok.context(ISampleContent)

def item_title(self): return self.context.title

View extenders

Additionally the views sub-classing from those base classes may be extended by other packages using so called view extenders, which are named adapters implementing horae.layout.interfaces.IViewExtender and adapting the view itself. If for example one would like to add an additional field to the aforementioned add form without touching the form itself:

System Message: WARNING/2 (<string>, line 105)

Literal block expected; none found.

from zope import schema from horae.layout import interfaces

class AddSampleContentExtender(grok.Adapter): grok.context(AddSampleContent) grok.implements(interfaces.IViewExtender) grok.name('addsamplecontentextender')

def pre_update(self): """ Called before the views update is called """ self.context.form_fields = self.context.form_fields + grok.Fields(additional_field=schema.TextLine( title=u'Additional field' ))

def pre_setUpWidgets(self, ignore_request=False): """ Called before the forms setUpWidgets is called """ # set custom widgets for fields using this method

def post_update(self): """ Called after the views update is called """ # set default values for fields using this method

def apply(self, obj, **data): """ Called when applying changes to an object """ obj.additional_field = data.get('additional_field', None)

System Message: WARNING/2 (<string>, line 131); backlink

Inline strong start-string without end-string.

def validate(self, action, data): """ Called when validating a form """ # do custom validation using this method

Viewlet managers

The following viewlet managers are registered in horae.layout.viewlets:

TopManager Viewlet manager rendered on top HeaderLeftManager Viewlet manager rendered on the left in the header HeaderRightManager Viewlet manager rendered on the right in the header ContentBeforeManager Viewlet manager rendered before the content ContentAfterManager Viewlet manager rendered after the content SidebarManager Viewlet manager rendered in the sidebar FooterManager Viewlet manager rendered in the footer

Table helper view

The table helper view is implemented in horae.layout.table and registered as a view named table. The view handles sorting, filtering and pagination of tabular data. An example usage of the view may be found in horae.layout.objects.ObjectOverview.

A simple usage may look like this:

System Message: WARNING/2 (<string>, line 195)

Literal block expected; none found.

from zope.component import getMultiAdapter from zope.schema import vocabulary

class SampleTableView(grok.View):

def render_table(self): table = getMultiAdapter((self.context, self.request), name=u'table') table.page_size = 10 table.columns = ( ('col1', u'Column 1'), ('col2', u'Column 2') ) table.sortable = { 'col1': 'col1', 'col2': 'col2' } table.filterable = { 'col1': vocabulary.SimpleVocabulary.fromValues([ 'Group 1', 'Group 2', 'Group 3' ]) } rows = [ {'col1': 'Group 1', 'col2': 'Row 1'}, {'col1': 'Group 1', 'col2': 'Row 2'}, {'col1': 'Group 1', 'col2': 'Row 3'}, {'col1': 'Group 2', 'col2': 'Row 4'}, {'col1': 'Group 2', 'col2': 'Row 5'}, {'col1': 'Group 2', 'col2': 'Row 6'}, {'col1': 'Group 3', 'col2': 'Row 7'}, {'col1': 'Group 3', 'col2': 'Row 8'}, {'col1': 'Group 4', 'col2': 'Row 9'}, ] filtering = table.filtering() if 'col1' in filtering: rows = [row for row in rows if row['col1'] in filtering['col1']] sort, reverse = table.sorting() if sort: rows = sorted(rows, key=lambda row: row[sort]) if reverse: rows = reversed(rows) table.rows = rows return table()

This would result in a table of two columns and nine rows which is sortable by both columns and the first column is filterable.


1.0a1 (2012-01-16)
  • Initial release

Subscribe to package updates

What does the lock icon mean?

Builds marked with a lock icon are only available via PyPM to users with a current ActivePython Business Edition subscription.

Need custom builds or support?

ActivePython Enterprise Edition guarantees priority access to technical support, indemnification, expert consulting and quality-assured language builds.

Plan on re-distributing ActivePython?

Get re-distribution rights and eliminate legal risks with ActivePython OEM Edition.