Forms Using Templates

The forms used to edit Packages and Groups in CKAN can be customised. This makes it easier to help users input data, helping them choose from sensible options or to use different data formats. This document sets out to show how this is achieved, without getting embroilled in the main CKAN code.

Note that this section deals with the form used to edit packages and groups, not the way they are displayed. Display is done in the CKAN templates.

Building a package form


You will firstly need to make a new controller in your extension. This should subclass PackageController like:

from ckan.controllers.package import PackageController
class PackageNew(PackageController):
    package_form = 'custom_package_form.html'

The package_form variable in the subclass will be used as the new form template.

It is recommended that you copy the package form (named new_package_form.html) and make modifications to it. However, it is possible to start from scratch.

In order for you to get this new controller pointed at correctly, your extension should look like the following:

class CustomForm(SingletonPlugin):


    def before_map(self, map):
        map.connect('/package/new', controller='ckanext.extension_name.controllers.PackageNewController:PackageNew', action='new')
        map.connect('/package/edit/{id}', controller='ckanext.extension_name.controllers.PackageNewController:PackageNew', action='edit')
        return map

    def after_map(self, map):
        return map

    def update_config(self, config):
        configure_template_directory(config, 'templates')

Replace extension_name with the name of your extension. This also assumes that custom_package_form.html is located in templates subdirectory of your extension i.e ckanext/extension_name/templates/custom_package_form.html.

Advanced Use

The PackageController has a more hooks to customize how and what data is displayed. These functions can be overridden subclass of PackageController:

_setup_template_variables(self, context)

This is for setting up new variables for your templates:


This defines a navl schema to customize validation and conversion to the database:


This defines a navl schema to customize conversion from the database to the form.

A complicated example of the use of these hooks can be found in extension ckanext-dgu.

Forms using FormAlchemy (depreciated)

This is now depreciated in order to get this to work your extention must implement IRoutes and have a before_map like the following:

class Plugin(SingletonPlugin):

    def before_map(self, map):
       map.connect('/package/new', controller='package_formalchemy', action='new')
       map.connect('/package/edit/{id}', controller='package_formalchemy', action='edit')
       return map

Location of related code

In the CKAN code, the majority of forms code is in ckan/forms.

  • ckan/forms/ - A common place for fields used by standard forms
  • ckan/forms/ - The FormBuilder class, which provides an easy way to define a form. It creates a FormAlchemy fieldset used in the CKAN controller code.
  • ckan/forms/ - This contains the ‘standard’ form, which is a good example and is useful to derive custom forms from.
  • ckan/forms/ - Contains the a government form, which serves as an example of using lots of extra fields for dates, geographical coverage, etc.

Building a package form


The PackageFormBuilder class initialises with the basic package form which we can then configure:

builder = PackageFormBuilder()

All the basic package fields are added to the form automatically - this currently includes: name, title, version, url, author, author_email, maintainer, maintainer_email, notes and license_id. In case this changes in future, consult the fields for table ‘Package’ in ckan/model/

To provide editing of other fields beyond the basic ones, you need to use add_field and select either an existing ConfiguredField in, or define your own. For example, the autocompleting tag entry field is defined as a field in and it is added to the standard form like this:


The basic fields (name, title, etc) and a few more (license, tags, resources) are defined for all packages. Additional information can be stored on each package in the ‘extra’ fields. Often we want to provide a nicer interface to these ‘extra’ fields to help keep consistency in format between the packages. For example, in the government form ( we have added a field for the release date. This is stored as a Package ‘extra’ with key ‘date_released’ and by using the DateExtraField, in the form the user is asked for a date.:


You can configure existing fields using the usual FormAlchemy Field options. For example, here we add a validator to a standard field:

builder.set_field_option('name', 'validate', package_name_validator)

Options are given keyword parameters by passing a dictionary. For example, this is how we set the notes field’s size:

builder.set_field_option('notes', 'textarea', {'size':'60x15'})

Fields in package forms are grouped together. You should specify which fields are displayed in which groups and in which order like this:

from sqlalchemy.util import OrderedDict
       ('Basic information', ['name', 'title', 'version', 'url']),
       ('Resources', ['resources']),
       ('Detail', ['author', 'author_email'])]))

To complete the form design you need to return the fieldset object. Ensure this is executed once - when your python form file is imported:

my_fieldset = builder.get_fieldset()

Field labels

The field labels are derived from the model key using a ‘prettify’ function. The default munge capitalises the first letter and changes underscores to spaces. You can write a more advanced function depending on your needs. Here is the template for a prettify function:

def prettify(field_name):
    return field_name.replace('_', ' ').capitalize())

If you write a new one, you tell the builder about it like this:



Package forms by default use the Genshi template ckan/package/form.html. If you want to use a modified one then specify it for example like this:


Hidden labels

A couple of common fields (ResourceField and ExtrasField currently) are designed to go in their own field group (see below) and without the usual field label. To hide the label, add these fields like this:

builder.add_field(common.ResourcesField('resources', hidden_label=True))

Instead of starting with just the basic fields, many people will want to edit the standard form, which already contains the resources, extra fields and customise that further. To achieve that you import the builder object like this:

import ckan.forms.package as package
builder = package.build_package_form()

Defining custom fields

If you want to define a completely new field then here is a useful template:

class MyField(common.ConfiguredField):
    def get_configured(self):
        return self.MyField(

    class MyField(formalchemy.Field):
        def sync(self):
            # edit self.model with using value self._deserialize()

    class MyRenderer(formalchemy.fields.FieldRenderer):
        def render(self, **kwargs):
            # return html of field editor based on self._value

        def _serialized_value(self):
            # take self._params and serialize them ready for rendering
            # or self.deserialize() into python value that can be saved
            # on a sync.

    def my_validator(self, val, field):
       if not ...:
           raise formalchemy.ValidationError('Invalid value')

More examples are in and further information can be obtained from the FormAlchemy documentation.

Using a custom form

To register your new form with CKAN you need to do three things.

  1. In your form you need a function that returns your new form’s field set.

For example you might add below your form code:

my_fieldset = builder.get_fieldset()

def get_fieldset(is_admin=False):
    return my_fieldset

(The is_admin parameter can be considered if you wish to return a different fieldset for administrator users.)

  1. You need to provide an ‘entry point’ into your code package so that CKAN can access your new form.

It is anticipated that your form code will live in a python package outside the CKAN main code package, managed by setuptools. The entry points are listed in the python package’s and you just need to add a category [ckan.forms] and list the function that returns:

from setuptools import setup, find_packages

    my_form = my_module.forms.my_form:get_fieldset

For this change to have an effect, you need to recreate the egg information, so run:

$ python egg_info
  1. Change an option in your CKAN pylons config file to switch to using the new form.

For example, your pylons config file will probably be ‘development.ini’ during development, when you ‘paster serve’ your CKAN app for testing.

You need to change the ‘package_form’ setting in the ‘[app:main]’ section to the name defined int he entry point. For example:

package_form = my_form
group_form = my_group_form
package_group_form = my_package_group_form

For this to have an effect you may need to restart the pylons (either by restarting the ‘serve’ command or the Apache host). Now go and edit a package and try out the new form!

You can also override the config file setting with a URL parameter in your browser. For example you might browse: