Tutorial: Creating an administration interface with FormAlchemy/GeoFormAlchemy ****************************************************************************** Many web applications require an administration interface to edit a website's content. Using `FormAlchemy `_ and `GeoFormAlchemy <#todo>`_ it is really easy to set up an automatic admin interface. FormAlchemy reads your SQLAlchemy models and automatically creates ready-to-use HTML forms, which can be customized to your needs. This document will describe how to set up an administration interface using FormAlchemy and GeoFormAlchemy in an existing MapFish application. Setup ===== Requirements ------------ The following chapters assume that you have installed the MapFish framework and that you have created a MapFish application for which you want to set up an admin interface. Installation ------------ First you will have to install FormAlchemy and GeoFormAlchemy. This can be done using ``easy_install``. Run the following two commands in your virtual Python environment:: (venv) $ easy_install formalchemy (venv) $ easy_install geoformalchemy Also make sure that you have installed the latest release of the library WebHelpers:: (venv) $ easy_install -U webhelpers Activate FormAlchemy/GeoFormAlchemy in your MapFish project ------------------------------------------------------------ FormAlchemy and GeoFormAlchemy both provide Pylons templates. The FormAlchemy template is intended for the creation of new Pylons projects, but it can also be used to update existing projects. But you will have to be careful that no files are overwritten. Run the following command to apply the GeoFormAlchemy template to your MapFish application. It will first apply the FormAlchemy template and then insert the files of GeoFormAlchemy. Replace ``tutorial`` with the actual name of your project:: (venv) $ paster create -t geo_fa tutorial [..] Enter admin_controller (Add formalchemy's admin controller) [False]: True Enter template_engine (mako/genshi/jinja2/etc: Template language) ['mako']: mako Enter sqlalchemy (True/False: Include SQLAlchemy 0.5 configuration) [False]: False When asked if the FormAlchemy ``admin controller`` should be added, enter ``True``. As ``Template language`` use ``mako``. And on the prompt ``Include SQLAlchemy 0.5 configuration``, reply with ``False``. The SQLAlchemy configuration was already installed when creating the MapFish application. After that you will be asked several times if a file should be overwritten. This is because the FormAlchemy template assumes an empty project. Always deny with ``n``:: Overwrite ./tutorial/tutorial/config/deployment.ini_tmpl [y/n/d/B/?] n Overwrite ./tutorial/tutorial/config/environment.py [y/n/d/B/?] n Overwrite ./tutorial/tutorial/lib/base.py [y/n/d/B/?] n Overwrite ./tutorial/tutorial/model/__init__.py [y/n/d/B/?] n Overwrite ./tutorial/tutorial/websetup.py [y/n/d/B/?] n Overwrite ./tutorial/development.ini [y/n/d/B/?] n Overwrite ./tutorial/setup.py [y/n/d/B/?] n Overwrite ./tutorial/tutorial/config/routing.py [y/n/d/B/?] n Then you will have to define a route to the admin interface controller. Open the file ``tutorial/config/routing.py`` and add the following lines after the ``CUSTOM ROUTES HERE`` comment:: def make_map(): # [..] # CUSTOM ROUTES HERE # Map the /admin url to FA's AdminController # Map static files map.connect('fa_static', '/admin/_static/{path_info:.*}', controller='admin', action='static') # Index page map.connect('admin', '/admin', controller='admin', action='models') map.connect('formatted_admin', '/admin.json', controller='admin', action='models', format='json') # Models map.resource('model', 'models', path_prefix='/admin/{model_name}', controller='admin') The administration interface is now set up. Start your application with ``paster serve development.ini`` and open the URL ``_ in your web browser. .. image:: _static/formalchemy-admin-empty.png :align: center :alt: FormAlchemy admin interface for Pylons Configuration ============= At the moment the admin interface is empty, you will have to tell FormAlchemy for which model classes it should create forms. Open the file ``tutorial/model/__init__.py`` and add imports for your models. For example like this:: """The application's model objects""" import sqlalchemy as sa from sqlalchemy import orm from tutorial.model import meta from tutorial.model.places import Place from tutorial.model.categories import Category # [..] .. hint:: See also `Pylons extensions: Administration interface `_ Then the GeoFormAlchemy extension has to be activated. Open the file ``tutorial/forms/__init__.py`` and add the following lines at the end of the file:: # [..] from geoformalchemy.base import GeometryFieldRenderer from geoalchemy import geometry FieldSet.default_renderers[geometry.Geometry] = GeometryFieldRenderer Restart your application and open or reload the URL ``_ in your web browser. You will now see a list of all your models that are parsed by FormAlchemy. Choose a model and a list of existing objects for this model will be displayed. .. image:: _static/formalchemy-admin-overview.png :align: center :alt: FormAlchemy admin interface: Overview of existing objects If you click on the ``New ...`` button or on a ``edit`` symbol, the overview page for a single object will be displayed. A `OpenLayers `_ map will be renderer for your geometry field by GeoFormAlchemy, in which you can add, edit and delete features using OpenLayers controls. .. image:: _static/geoformalchemy-admin-detail.png :align: center :alt: FormAlchemy/GeoFormAlchemy admin interface: Detail page Customization ============= FormAlchemy offers a number of ways to customize your forms, the following two chapters will describe two of them. If you want to do advanced customizations like writing your `own field renderer `_, using your `own template engine `_ or creating your `own field validator `_, please refer to the `FormAlchemy documentation `_. Field modifications ------------------- Single fields of your model can easily be customized using the FormAlchemy field modification methods. For example you can exclude fields, so that they are not shown in the form, set a label for a field, mark a field as ``required`` or render a string field in a ``textarea``. These modifications can be set in the file ``tutorial/forms/__init__.py``. Open the file and add the following lines:: Place = FieldSet(model.places.Place) Place.configure(options=[Place.the_geom.label('Geometry').required()]) Here we are creating a custom ``FieldSet`` for the model class ``Place``. Note that the custom ``FieldSet`` **must have the same name** as your model class. Using the method `configure( ) `_ we now can customize the form for our model. In the above example we are setting a label for the field ``the_geom`` and are marking the field as ``required`` by calling the methods ``label()`` and ``required()`` on the field. These two modifications are *chained*, you can also add further modifications. You can find a list of modifications in the FormAlchemy documentation in chapter `Forms: Field Modification `_. The rendering of geometry fields can be customized with additional options. For example the following statement called on the field ``the_geom`` of the custom ``FieldSet`` changes the background map:: Place.the_geom.set(options=[ ('map_srid', 900913), ('base_layer', 'new OpenLayers.Layer.OSM("OSM")') ]) .. _geoformalchemy-options: **The following options are available in GeoFormAlchemy:** ``default_lat`` and ``default_lon`` If the geometry is ``None`` or when creating a new geometry, the map is centered at (default_lon, default_lat). Otherwise the map is centered at the centroid of the geometry. ``zoom`` The zoom-level on start-up. ``map_width`` and ``map_height`` The size of the ``DIV`` container in which the map is displayed. ``base_layer`` The OpenLayers layer which will be used as background map, for example:: ('base_layer', 'new OpenLayers.Layer.OSM("OSM")') ``map_srid`` If the map uses a different CRS than the geometries, the geometries will be reprojected to this CRS. For example:: ('map_srid', 900913) ``openlayers_lib`` The path to the OpenLayers JavaScript library, for example to use the OpenLayers library packaged with MapFish use the following path:: ('openlayers_lib', '/mfbase/openlayers/lib/OpenLayers.js') ``show_map`` (default: ``True``) If ``show_map`` is set to ``False``, the geometry will be displayed as WKT string inside a text input field. Template files -------------- If you want to change the look of your forms, you can modify the template files used by FormAlchemy and GeoFormAlchemy. The template files are located in the folder ``tutorial/templates/forms``. ``fieldset.mako`` and ``fieldset_readonly.mako`` are used for displaying a single object, ``grid.mako`` and ``grid_readonly.mako`` are rendered as model overview page. The overall design can be changed in the file ``restfieldset.mako``. The CSS stylesheet and the images used in the admin interface are part of the FormAlchemy library and can not be modified directly. If you want to change them, you can download the original files from the `FormAlchemy repository `_ to ``tutorial/public`` and then adapt the paths in the template files. GeoFormAlchemy uses the template files ``map_js.mako`` and ``map.mako``. In ``map.mako`` you can set most of the options that you can also use as :ref:`field modification `. But unlike to field modifications, the options set in the template file are used for the geometry fields of all models, whereas the options set as field modification are only used for the field they were set on. :: <% # default configuration options that will be used when # no field options were set options = {} options['default_lon'] = 10 options['default_lat'] = 45 options['zoom'] = 4 options['map_width'] = 512 options['map_height'] = 256 options['base_layer'] = 'new OpenLayers.Layer.WMS("WMS", "http://labs.metacarta.com/wms/vmap0", {layers: "basic"})' options['openlayers_lib'] = 'http://openlayers.org/api/OpenLayers.js' %> If you want to customize the OpenLayers map, for example to add a further OpenLayers control or to add a second background layer, modify the file ``map_js.mako``.