This is a pre-production deployment of Warehouse, however changes made here WILL affect the production instance of PyPI.
Latest Version Dependencies status unknown Test status unknown Test coverage unknown
Project Description


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 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:

If this parameter is set to any truth value only the views result is rendered without the whole layout put around.
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:

import grok

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

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

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

    def add(self, 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:

class EditSampleContent(layout.EditForm):
    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:

class DisplaySampleContent(layout.DisplayForm):
    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:

class DeleteSampleContent(layout.DeleteForm):

    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:

from zope import schema
from horae.layout import interfaces

class AddSampleContentExtender(grok.Adapter):

    def pre_update(self):
        """ Called before the views update is called
        self.context.form_fields = self.context.form_fields + \
                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)

    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:

Viewlet manager rendered on top
Viewlet manager rendered on the left in the header
Viewlet manager rendered on the right in the header
Viewlet manager rendered before the content
Viewlet manager rendered after the content
Viewlet manager rendered in the sidebar
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:

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
Release History

Release History


This version

History Node

TODO: Figure out how to actually get changelog content.

Changelog content for this version goes here.

Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Show More

Download Files

Download Files

TODO: Brief introduction on what you do with files - including link to relevant help section.

File Name & Checksum SHA256 Checksum Help Version File Type Upload Date
horae.layout-1.0a1.tar.gz (57.4 kB) Copy SHA256 Checksum SHA256 Source Jan 16, 2012

Supported By

WebFaction WebFaction Technical Writing Elastic Elastic Search Pingdom Pingdom Monitoring Dyn Dyn DNS Sentry Sentry Error Logging CloudAMQP CloudAMQP RabbitMQ Heroku Heroku PaaS Kabu Creative Kabu Creative UX & Design Fastly Fastly CDN DigiCert DigiCert EV Certificate Rackspace Rackspace Cloud Servers DreamHost DreamHost Log Hosting