Skip to content

Commit

Permalink
[#1841] document custom converters and validators
Browse files Browse the repository at this point in the history
  • Loading branch information
wardi committed Aug 13, 2014
1 parent 3770777 commit dce2b55
Showing 1 changed file with 101 additions and 2 deletions.
103 changes: 101 additions & 2 deletions doc/extensions/adding-custom-fields.rst
Expand Up @@ -32,8 +32,8 @@ For example, the schemas can allow optional values by using the
:func:`~ckan.lib.navl.validators.ignore_missing` validator or check that a
dataset exists using :func:`~ckan.logic.validators.package_id_exists`. A list
of available validators and converters can be found at the :doc:`validators`
and :doc:`converters`. You can also define your own validators for custom
validation.
and :doc:`converters`. You can also define your own
:ref:`custom-validators`.

We will be customizing these schemas to add our additional fields. The
:py:class:`~ckan.plugins.interfaces.IDatasetForm` interface allows us to
Expand Down Expand Up @@ -189,6 +189,105 @@ with:
:start-after: p.implements(p.IDatasetForm)
:end-before: def show_package_schema(self):


.. _custom-validators:

Custom validators and converters
--------------------------------

You may define custom validators and converters in your extensions and
you can share converters and validators between extensions by registering
them with either the :py:class:`~ckan.plugins.interfaces.IValidators` or
:py:class:`~ckan.plugins.interfaces.IConverters` interfaces.

Any of the following objects may be used as validators/converters as part
of a custom dataset, group or organization schema. CKAN's validation
code will check for and attempt to use them in this order:

1. a `formencode Validator class <http://www.formencode.org/en/latest/Validator.html>`_ (not discussed)

2. a formencode Validator instance (not discussed)

3. a callable object taking a single parameter: ``validator(value)``

4. a callable object taking four parameters:
``validator(key, converted_data, errors, context)``

5. a callable object taking two parameters
``validator(value, context)``


``validator(value)``
^^^^^^^^^^^^^^^^^^^^

The simplest form of validator is a callable taking a single
parameter. For example::

from ckan.plugins.toolkit import Invalid

def starts_with_b(value):
if not value.startswith('b'):
raise Invalid("Doesn't start with b")
return value

The ``starts_with_b`` validator will allow only values starting with 'b',
and cause a
validation error otherwise. On a web form this validation error would
appear next to the field to which the validator was applied.

``return value`` must be used by validators in this form to when accepting data
or the value will be converted to None. This makes this form useful
for converters as well, because the return value will
replace the field value passed::

def embiggen(value):
return value.upper()

The ``embiggen`` converter will convert values passed to all-uppercase.


``validator(value, context)``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Validators and converters that need access to the database or information
about the user may be written as a callable taking two parameters.
``context['session']`` is the sqlalchemy session object and
``context['user']`` is the username of the logged-in user::

from ckan.plugins.toolkit import Invalid

def fred_only(value, context):
if value and context['user'] != 'fred':
raise Invalid('only fred may set this value')
return value

Otherwise this is the same as the single-parameter form above.


``validator(key, flattened_data, errors, context)``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Validators and converters that need to access or update fields other than
the one they are applied to may be written as a callable taking four
parameters. ``context`` is the same value passed to the two-parameter
form above.

This form of validator or converter is passed the all the fields and
errors for all the fields in a "flattened" form. The validator must fetch
values from ``flattened_data`` and converters may replace values in
``flattened_data``.

``key`` is the flattened key for the field to which this validator was
applied. For example ``('notes',)`` for the dataset notes field or
``('resources', 0, 'url')`` for the url of the first resource of the dataset.
These flattened keys are used in the ``flattened_data`` and ``errors``
dicts passed.

Note that this form is tricky to use because some of the values in
``flattened_data`` will have had validators and converters applied
but other fields won't.


Tag vocabularies
----------------
If you need to add a custom field where the input options are restricted to a
Expand Down

0 comments on commit dce2b55

Please sign in to comment.