| 1 | Using spatial databases with MapFish |
|---|
| 2 | ************************************ |
|---|
| 3 | |
|---|
| 4 | Since release 2.0 MapFish uses the `SQLAlchemy <http://www.sqlalchemy.org/>`_ extension |
|---|
| 5 | `GeoAlchemy <http://www.geoalchemy.org/>`_ that provides support for geospatial databases. |
|---|
| 6 | By using GeoAlchemy, MapFish can also be used with all database systems supported by GeoAlchemy. |
|---|
| 7 | |
|---|
| 8 | The following document is going to describe how to set up the databases and how to |
|---|
| 9 | use them. |
|---|
| 10 | |
|---|
| 11 | Using PostgreSQL/PostGIS |
|---|
| 12 | ======================== |
|---|
| 13 | |
|---|
| 14 | Installation |
|---|
| 15 | ------------ |
|---|
| 16 | |
|---|
| 17 | If you followed the `installation guide <../installation.html>`_, then you already |
|---|
| 18 | have installed PostgreSQL/PostGIS and you can skip this section. If not, run the |
|---|
| 19 | following command from a terminal to install `PostgreSQL <http://www.postgresql.org/>`_, |
|---|
| 20 | `PostGIS <http://www.postgis.org/>`_ and the required library `GEOS <http://trac.osgeo.org/geos/>`_:: |
|---|
| 21 | |
|---|
| 22 | $ sudo apt-get install libgeos-3.0.0 postgresql postgis postgresql-8.3-postgis |
|---|
| 23 | |
|---|
| 24 | Further information about installing PostGIS can be found in the `PostGIS documentation |
|---|
| 25 | <http://postgis.refractions.net/docs/ch02.html>`_. |
|---|
| 26 | |
|---|
| 27 | Setting up a spatially-enabled database |
|---|
| 28 | ---------------------------------------- |
|---|
| 29 | |
|---|
| 30 | Creating a spatially-enabled database is slightly different from creating an ordinary database. Run |
|---|
| 31 | the following commands to create the database ``gis``:: |
|---|
| 32 | |
|---|
| 33 | sudo su postgres |
|---|
| 34 | createdb -E UNICODE gis |
|---|
| 35 | createlang plpgsql gis |
|---|
| 36 | psql -d gis -f /usr/share/postgresql-8.3-postgis/lwpostgis.sql |
|---|
| 37 | psql -d gis -f /usr/share/postgresql-8.3-postgis/spatial_ref_sys.sql |
|---|
| 38 | psql -d gis -c "SELECT postgis_full_version()" |
|---|
| 39 | exit |
|---|
| 40 | |
|---|
| 41 | The last query will inform you about the version of your PostGIS installation. |
|---|
| 42 | |
|---|
| 43 | In most cases you do not want to access your database from a web application as ``root``. The following |
|---|
| 44 | commands create a user ``www-data`` and grant access rights to this user for the database ``gis``:: |
|---|
| 45 | |
|---|
| 46 | sudo su postgres |
|---|
| 47 | createuser -P www-data |
|---|
| 48 | psql gis |
|---|
| 49 | grant all on database gis to "www-data"; |
|---|
| 50 | grant select on spatial_ref_sys to "www-data"; |
|---|
| 51 | grant all on geometry_columns to "www-data"; |
|---|
| 52 | \q |
|---|
| 53 | exit |
|---|
| 54 | |
|---|
| 55 | .. hint:: |
|---|
| 56 | |
|---|
| 57 | Depending on if your user should be allowed to create tables, to insert/update rows or just |
|---|
| 58 | to read, you may want to adjust the privileges (see the `PostgreSQL documentation |
|---|
| 59 | <http://www.postgresql.org/docs/8.3/interactive/sql-grant.html>`_ for further |
|---|
| 60 | information). |
|---|
| 61 | |
|---|
| 62 | Now it is time to create tables in your database. You can either let SQLAlchemy/GeoAlchemy do |
|---|
| 63 | that for you (see :ref:`setup-app`) or you can manually create tables (see `Creating a Spatial Table |
|---|
| 64 | <http://postgis.refractions.net/docs/ch04.html#Create_Spatial_Table>`_ in the PostGIS documentation). |
|---|
| 65 | |
|---|
| 66 | You can also use the tool `shp2pgsql <http://postgis.refractions.net/docs/ch04.html#shp2pgsql_usage>`_ |
|---|
| 67 | to create a table from a Shapefile. For example to create the table for this countries Shapefile |
|---|
| 68 | (:download:`countries.zip <_static/countries.zip>`), you would have to do this:: |
|---|
| 69 | |
|---|
| 70 | unzip countries.zip |
|---|
| 71 | sudo su postgres |
|---|
| 72 | shp2pgsql -W utf8 -s 4326 countries.shp countries | psql -d gis |
|---|
| 73 | exit |
|---|
| 74 | |
|---|
| 75 | And to check that everything is ok, we can query the row count. Additionally we need to grant |
|---|
| 76 | the access to this table to user ``www-data`` in order to allow access from MapFish server in a web environment:: |
|---|
| 77 | |
|---|
| 78 | sudo su postgres |
|---|
| 79 | psql gis |
|---|
| 80 | \d |
|---|
| 81 | select count(1) from countries; |
|---|
| 82 | GRANT ALL ON countries TO "www-data"; |
|---|
| 83 | \q |
|---|
| 84 | exit |
|---|
| 85 | |
|---|
| 86 | Configuration |
|---|
| 87 | -------------- |
|---|
| 88 | |
|---|
| 89 | Once the database is set up, you only have to change the database connection string in the |
|---|
| 90 | configuration file of your MapFish application. Open your configuration file, for example |
|---|
| 91 | ``development.ini``, and replace the line:: |
|---|
| 92 | |
|---|
| 93 | sqlalchemy.url = sqlite:///%(here)s/development.db |
|---|
| 94 | |
|---|
| 95 | by this one:: |
|---|
| 96 | |
|---|
| 97 | sqlalchemy.url = postgresql://www-data:www-data@localhost/gis |
|---|
| 98 | |
|---|
| 99 | Using MySQL |
|---|
| 100 | ============ |
|---|
| 101 | |
|---|
| 102 | Installation |
|---|
| 103 | ------------ |
|---|
| 104 | |
|---|
| 105 | On Debian-based systems, MySQL can be installed with:: |
|---|
| 106 | |
|---|
| 107 | $ sudo apt-get install mysql-server mysql-client |
|---|
| 108 | |
|---|
| 109 | .. hint:: |
|---|
| 110 | More information about installing MySQL can be found in the `MySQL manual |
|---|
| 111 | <http://dev.mysql.com/doc/refman/5.5/en/installing.html>`_. |
|---|
| 112 | |
|---|
| 113 | You will also have to install a Python driver for MySQL. Run the following command |
|---|
| 114 | inside the virtual environment to install the library `mysql-python |
|---|
| 115 | <http://pypi.python.org/pypi/MySQL-python/>`_:: |
|---|
| 116 | |
|---|
| 117 | (venv) $ easy_install mysql-python |
|---|
| 118 | |
|---|
| 119 | |
|---|
| 120 | Setting up a spatially-enabled database |
|---|
| 121 | ---------------------------------------- |
|---|
| 122 | |
|---|
| 123 | For MySQL setting up a spatial database is the same as setting up an ordinary database:: |
|---|
| 124 | |
|---|
| 125 | mysql -u root -p |
|---|
| 126 | create database gis; |
|---|
| 127 | quit |
|---|
| 128 | |
|---|
| 129 | .. note:: |
|---|
| 130 | When creating a database, or directly when creating a table, you can specify the |
|---|
| 131 | `storage engine <http://dev.mysql.com/doc/refman/5.5/en/storage-engines.html>`_ |
|---|
| 132 | (MyISAM/InnoDB/..) that should be used for the tables. Note that currently only |
|---|
| 133 | MyISAM uses a `R-tree <http://en.wikipedia.org/wiki/R-tree>`_ for spatial indexes that |
|---|
| 134 | optimize spatial queries (see `Optimizing Spatial Analysis |
|---|
| 135 | <http://dev.mysql.com/doc/refman/5.5/en/optimizing-spatial-analysis.html>`_ in the MySQL |
|---|
| 136 | manual). |
|---|
| 137 | |
|---|
| 138 | To create a database user that can be used for accessing the database from a web |
|---|
| 139 | application, execute the following statements:: |
|---|
| 140 | |
|---|
| 141 | mysql -u root -p |
|---|
| 142 | create user 'www-data' identified by 'www-data'; |
|---|
| 143 | grant all on gis.* to 'www-data'; |
|---|
| 144 | quit |
|---|
| 145 | |
|---|
| 146 | Tables with geometry columns can be created like any other table using the `geometry type |
|---|
| 147 | <http://dev.mysql.com/doc/refman/5.5/en/mysql-spatial-datatypes.html>`_ as column data type |
|---|
| 148 | (see `Creating Spatial Columns <http://dev.mysql.com/doc/refman/5.5/en/creating-spatial-columns.html>`_ |
|---|
| 149 | in the MySQL manual), for example:: |
|---|
| 150 | |
|---|
| 151 | mysql -u root -p |
|---|
| 152 | use gis; |
|---|
| 153 | CREATE TABLE points (id INTEGER AUTO_INCREMENT, |
|---|
| 154 | name VARCHAR(40), |
|---|
| 155 | geom POINT NOT NULL, |
|---|
| 156 | SPATIAL INDEX(geom), |
|---|
| 157 | PRIMARY KEY(id)); |
|---|
| 158 | quit |
|---|
| 159 | |
|---|
| 160 | .. note:: |
|---|
| 161 | If you want to use a `spatial index <http://dev.mysql.com/doc/refman/5.5/en/creating-spatial-indexes.html>`_ |
|---|
| 162 | for your geometry column, the column must be declared as ``NOT NULL``. |
|---|
| 163 | |
|---|
| 164 | Configuration |
|---|
| 165 | -------------- |
|---|
| 166 | |
|---|
| 167 | Set the database connection string in the configuration file of your MapFish application |
|---|
| 168 | (for example ``development.ini``) by replacing the line:: |
|---|
| 169 | |
|---|
| 170 | sqlalchemy.url = sqlite:///%(here)s/development.db |
|---|
| 171 | |
|---|
| 172 | by this one:: |
|---|
| 173 | |
|---|
| 174 | sqlalchemy.url = mysql://www-data:www-data@localhost/gis |
|---|
| 175 | |
|---|
| 176 | Limitations |
|---|
| 177 | ------------ |
|---|
| 178 | |
|---|
| 179 | * MySQL does not support coordinate system transformations for geometries. All |
|---|
| 180 | your spatial data must be in the same spatial reference system. |
|---|
| 181 | * Not all methods of the *OpenGIS® Simple Features Specifications For SQL* are supported by MySQL, |
|---|
| 182 | for example ``distance()`` or ``buffer()`` are not part of the stable release. A list of these functions can be found |
|---|
| 183 | `here <http://dev.mysql.com/doc/refman/5.5/en/functions-that-create-new-geometries-from-existing-ones.html#spatial-operators>`_. |
|---|
| 184 | Other functions only operate on the minimum bounding rectangle (MBR) of the geometries, a list of |
|---|
| 185 | these functions can be found in `the MySQL manual <http://dev.mysql.com/doc/refman/5.5/en/functions-that-test-spatial-relationships-between-geometries.html>`_. |
|---|
| 186 | Because of that, features queried through the `MapFish Protocol <../protocol.html>`_ |
|---|
| 187 | are also selected using the MBR. |
|---|
| 188 | |
|---|
| 189 | Using SQLite/Spatialite |
|---|
| 190 | ======================= |
|---|
| 191 | |
|---|
| 192 | Installation |
|---|
| 193 | ------------ |
|---|
| 194 | |
|---|
| 195 | Installation of Spatialite |
|---|
| 196 | """"""""""""""""""""""""""""""""" |
|---|
| 197 | |
|---|
| 198 | Spatialite requires the libraries `GEOS <http://trac.osgeo.org/geos/>`_ and `PROJ4 |
|---|
| 199 | <http://proj.osgeo.org/>`_, which in most cases you will have already installed |
|---|
| 200 | together with PostGIS:: |
|---|
| 201 | |
|---|
| 202 | $ sudo apt-get install libgeos-c1 proj |
|---|
| 203 | |
|---|
| 204 | .. note:: |
|---|
| 205 | |
|---|
| 206 | Spatialite expects libgeos 3.1.1, but it can also be used with any 3.0.x release. You just have to |
|---|
| 207 | create a symbolic link:: |
|---|
| 208 | |
|---|
| 209 | sudo ln /usr/lib/libgeos-3.0.0.so /usr/lib/libgeos-3.1.1.so |
|---|
| 210 | |
|---|
| 211 | Now download the precompiled Spatialite library ``libspatialite`` from the `Spatialite download page |
|---|
| 212 | <http://www.gaia-gis.it/spatialite/binaries.html>`_ and unzip the archive to ``/usr/local/lib/libspatialite`` or |
|---|
| 213 | into a folder of your convenience:: |
|---|
| 214 | |
|---|
| 215 | wget http://www.gaia-gis.it/spatialite/libspatialite-linux-x86-2.3.1.tar.gz |
|---|
| 216 | sudo tar -xvf libspatialite-linux-x86-2.3.1.tar.gz -C /usr/local/lib/ |
|---|
| 217 | sudo mv /usr/local/lib/libspatialite-* /usr/local/lib/libspatialite |
|---|
| 218 | |
|---|
| 219 | .. hint:: |
|---|
| 220 | |
|---|
| 221 | On Ubuntu 9.10+ you can install the Spatialite library as package ``libspatialite2`` directly |
|---|
| 222 | from the repositories. |
|---|
| 223 | |
|---|
| 224 | .. note:: |
|---|
| 225 | |
|---|
| 226 | The precompiled libraries for Spatialite only work on 32-bit systems, if you are using a 64-bit system |
|---|
| 227 | you will have to compile by yourself. To do so, download the source code for ``libspatialite-amalgamation`` |
|---|
| 228 | from the `Spatialite website <http://www.gaia-gis.it/spatialite/sources.html>`_. Make sure that you |
|---|
| 229 | also have installed the package ``libgeos-dev``. Unzip the source archive and compile by using the following commands |
|---|
| 230 | (you may want to change the ``prefix`` path, the compiled library will be copied there):: |
|---|
| 231 | |
|---|
| 232 | ./configure --prefix=/home/c2c/libspatialite --with-geos-lib=/usr/lib --with-proj-lib=/usr/lib |
|---|
| 233 | make install |
|---|
| 234 | |
|---|
| 235 | If you are receiving the error message ``cannot find -lstdc++``, you may have to create a |
|---|
| 236 | symbolic link for this library:: |
|---|
| 237 | |
|---|
| 238 | sudo ln /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so |
|---|
| 239 | |
|---|
| 240 | Further information about compiling ``libspatialite`` can be found here: |
|---|
| 241 | `How to build libspatialite <http://www.gaia-gis.it/spatialite/how_to_build_libspatialite.html>`_. |
|---|
| 242 | |
|---|
| 243 | |
|---|
| 244 | Installation of pysqlite2 |
|---|
| 245 | """""""""""""""""""""""""" |
|---|
| 246 | |
|---|
| 247 | Even though Python 2.5+ contains the SQLite driver `pysqlite2 <http://trac.edgewall.org/wiki/PySqlite>`_, |
|---|
| 248 | you have to compile it by yourself. The Spatialite library is used in SQLite as extension, and by default |
|---|
| 249 | loading external extensions is disabled in *pysqlite2*. |
|---|
| 250 | |
|---|
| 251 | To compile *pysqlite2* you will have to install the SQLite header files:: |
|---|
| 252 | |
|---|
| 253 | sudo apt-get install libsqlite3-dev |
|---|
| 254 | |
|---|
| 255 | Download the *pysqlite2* source code from `pysqlite2 - Downloads |
|---|
| 256 | <http://code.google.com/p/pysqlite/downloads/list?can=3&q=*.tar.gz>`_ and unzip it into your |
|---|
| 257 | MapFish virtual environment. |
|---|
| 258 | |
|---|
| 259 | Then open the file ``setup.cfg`` and comment out the line ``define=SQLITE_OMIT_LOAD_EXTENSION``:: |
|---|
| 260 | |
|---|
| 261 | [build_ext] |
|---|
| 262 | #define= |
|---|
| 263 | #include_dirs=/usr/local/include |
|---|
| 264 | #library_dirs=/usr/local/lib |
|---|
| 265 | libraries=sqlite3 |
|---|
| 266 | #define=SQLITE_OMIT_LOAD_EXTENSION |
|---|
| 267 | |
|---|
| 268 | Now you can compile and setup *pysqlite2* with:: |
|---|
| 269 | |
|---|
| 270 | (venv) $ python setup.py install |
|---|
| 271 | |
|---|
| 272 | .. note:: |
|---|
| 273 | |
|---|
| 274 | If you are running into ``Segmentation Fault`` errors using this build, you can try to do |
|---|
| 275 | a ``static build``. This will download the latest SQLite3 amalgation file and link it |
|---|
| 276 | internally:: |
|---|
| 277 | |
|---|
| 278 | (venv) $ python setup.py build_static install |
|---|
| 279 | |
|---|
| 280 | Setting up a spatially-enabled database |
|---|
| 281 | ---------------------------------------- |
|---|
| 282 | |
|---|
| 283 | Creating a database can be done using ``spatialite-gui`` or by using the CLI client ``spatialite``. In |
|---|
| 284 | the following we will use ``spatialite``, but you can also use ``spatialite-gui`` to execute the commands. |
|---|
| 285 | |
|---|
| 286 | .. hint:: |
|---|
| 287 | |
|---|
| 288 | You can get ``spatialite-gui`` from `the Spatialite website <http://www.gaia-gis.it/spatialite/binaries.html>`_, |
|---|
| 289 | also take a look at the `Quickguide for spatialite-gui |
|---|
| 290 | <http://www.gaia-gis.it/spatialite/spatialite-gui-notes.pdf>`_ (PDF). |
|---|
| 291 | |
|---|
| 292 | First you have to download the package ``spatialite-tools`` from `Spatialite Downloads |
|---|
| 293 | <http://www.gaia-gis.it/spatialite/binaries.html>`_ and |
|---|
| 294 | the script ``init_spatialite-2.3.sql`` from `Spatialite Ressources |
|---|
| 295 | <http://www.gaia-gis.it/spatialite/resources.html>`_. The scripts creates the ``geometry_columns`` and |
|---|
| 296 | ``spatial_ref_sys`` metadata tables and also inserts a collection of spatial reference systems. |
|---|
| 297 | |
|---|
| 298 | Start the Spatialite client by calling:: |
|---|
| 299 | |
|---|
| 300 | spatialite gis.sqlite |
|---|
| 301 | |
|---|
| 302 | This will create the file ``gis.sqlite``, if it does not exist already. Then execute the script |
|---|
| 303 | ``init_spatialite-2.3.sql``:: |
|---|
| 304 | |
|---|
| 305 | .read init_spatialite-2.3.sql ASCII |
|---|
| 306 | |
|---|
| 307 | Now you can create a table with a geometry column. This is done in two steps: First we create a plain SQLite |
|---|
| 308 | table without the geometry column, and then we add the geometry column using the function |
|---|
| 309 | `AddGeometryColumn() <http://www.gaia-gis.it/spatialite-2.3.0/spatialite-sql-2.3.0.html#p16>`_:: |
|---|
| 310 | |
|---|
| 311 | CREATE TABLE points (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(40)); |
|---|
| 312 | SELECT AddGeometryColumn('points', 'geom', 4326, 'POINT', 2); |
|---|
| 313 | |
|---|
| 314 | .. hint:: |
|---|
| 315 | |
|---|
| 316 | You can also create a table from a Shapefile with ``.loadshp`` (see also |
|---|
| 317 | `Creating a new SpatiaLite db and populating it |
|---|
| 318 | <http://www.gaia-gis.it/spatialite/spatialite-tutorial-2.3.1.html#t3.2>`_):: |
|---|
| 319 | |
|---|
| 320 | .loadshp countries Countries utf-8 |
|---|
| 321 | |
|---|
| 322 | And you can even execute queries directly on Shapefiles without copying the data into a table |
|---|
| 323 | (see also `Performing SQL queries directly on shapefiles |
|---|
| 324 | <http://www.gaia-gis.it/spatialite/spatialite-tutorial-2.3.1.html#t6>`_):: |
|---|
| 325 | |
|---|
| 326 | CREATE VIRTUAL TABLE virtual_countries USING VirtualShape('/home/c2c/data/countries', utf-8, 4326); |
|---|
| 327 | select count(*) from virtual_countries where |
|---|
| 328 | MBRWithin(Geometry, GeomFromText('POLYGON((0 0, 40 0, 40 40, 0 40, 0 0))', 4326)); |
|---|
| 329 | |
|---|
| 330 | Currently only read operations are supported, but still ``virtual tables`` are a good option |
|---|
| 331 | to publish a Shapefile with MapFish. |
|---|
| 332 | |
|---|
| 333 | Configuration |
|---|
| 334 | -------------- |
|---|
| 335 | |
|---|
| 336 | When using ``spatialite-gui`` and ``spatialite`` the Spatialite library is automatically |
|---|
| 337 | loaded as extension. But when connecting to a Spatialite database using a ordinary SQLite driver, |
|---|
| 338 | you have to load the Spatialite library manually. |
|---|
| 339 | |
|---|
| 340 | In MapFish, database connections are managed by SQLAlchemy. Every time SQLAlchemy opens a new |
|---|
| 341 | connection to a Spatalite database, the Spatialite library must be loaded. This can be done by |
|---|
| 342 | setting up a `PoolListener <http://www.sqlalchemy.org/docs/reference/sqlalchemy/interfaces.html#sqlalchemy.interfaces.PoolListener>`_. |
|---|
| 343 | |
|---|
| 344 | Open the file ``model/__init__.py`` and modify the method ``init_model(engine)``, so that |
|---|
| 345 | it looks like this:: |
|---|
| 346 | |
|---|
| 347 | # ... |
|---|
| 348 | |
|---|
| 349 | from sqlalchemy.dialects.sqlite.base import SQLiteDialect |
|---|
| 350 | from sqlalchemy.interfaces import PoolListener |
|---|
| 351 | |
|---|
| 352 | # ... |
|---|
| 353 | |
|---|
| 354 | def init_model(engine): |
|---|
| 355 | sm = orm.sessionmaker(autoflush=True, autocommit=False, bind=engine) |
|---|
| 356 | |
|---|
| 357 | meta.engine = engine |
|---|
| 358 | meta.Session = orm.scoped_session(sm) |
|---|
| 359 | |
|---|
| 360 | if isinstance(engine.dialect, SQLiteDialect): |
|---|
| 361 | class SpatialiteConnectionListener(PoolListener): |
|---|
| 362 | def connect(self, dbapi_con, con_record): |
|---|
| 363 | dbapi_con.enable_load_extension(True) |
|---|
| 364 | dbapi_con.execute("select load_extension('/usr/local/lib/libspatialite/lib/libspatialite.so')") |
|---|
| 365 | dbapi_con.enable_load_extension(False) |
|---|
| 366 | |
|---|
| 367 | engine.pool.add_listener(SpatialiteConnectionListener()) |
|---|
| 368 | |
|---|
| 369 | # ... |
|---|
| 370 | |
|---|
| 371 | Now you just have to set the database connection string in the configuration file of your MapFish application |
|---|
| 372 | (for example ``development.ini``) by replacing the line:: |
|---|
| 373 | |
|---|
| 374 | sqlalchemy.url = sqlite:///%(here)s/development.db |
|---|
| 375 | |
|---|
| 376 | by this one:: |
|---|
| 377 | |
|---|
| 378 | sqlalchemy.url = sqlite:////home/c2c/data/gis.sqlite |
|---|
| 379 | |
|---|
| 380 | .. hint:: |
|---|
| 381 | |
|---|
| 382 | The number of slashs to the right of ``sqlite:`` depends on if you are using a relative or |
|---|
| 383 | absolute path, see also `SQLite: Connect Strings |
|---|
| 384 | <http://www.sqlalchemy.org/docs/reference/dialects/sqlite.html#connect-strings>`_. |
|---|
| 385 | |
|---|
| 386 | Using Oracle |
|---|
| 387 | ======================= |
|---|
| 388 | |
|---|
| 389 | Installation |
|---|
| 390 | ------------- |
|---|
| 391 | |
|---|
| 392 | The Python driver `cx_Oracle <http://cx-oracle.sourceforge.net/>`_ requires an Oracle client or |
|---|
| 393 | server installation. If your MapFish application is running on the same system as your |
|---|
| 394 | Oracle database, you can skip the section :ref:`instant-client`. |
|---|
| 395 | |
|---|
| 396 | .. note:: |
|---|
| 397 | |
|---|
| 398 | The installation of Oracle database server software is not covered in this tutorial, |
|---|
| 399 | please refer to the `Oracle Database Documentation <http://www.oracle.com/pls/db112/portal.portal_db?selected=11&frame=>`_. |
|---|
| 400 | |
|---|
| 401 | For guidance on installing Oracle on Debian based systems, take a look at these two tutorials: |
|---|
| 402 | |
|---|
| 403 | - `Installing Oracle 11gR2 on Ubuntu 9.10 <http://mikesmithers.wordpress.com/2010/03/14/installing-oracle-11gr2-on-ubuntu-9-10/>`_ |
|---|
| 404 | - `Installing Oracle 11gR1 on Ubuntu 8.10 Intrepid Ibex <http://www.pythian.com/news/1355/installing-oracle-11gr1-on-ubuntu-810-intrepid-ibex/>`_ |
|---|
| 405 | |
|---|
| 406 | .. _instant-client: |
|---|
| 407 | |
|---|
| 408 | Installation of Oracle Instant Client |
|---|
| 409 | """""""""""""""""""""""""""""""""""""" |
|---|
| 410 | |
|---|
| 411 | The easiest way to get an Oracle Client is installing *Oracle Instant Client*. Download the following |
|---|
| 412 | two packages for your operating system from `Instant Client Downloads <http://www.oracle.com/technology/software/tech/oci/instantclient/index.html>`_: |
|---|
| 413 | |
|---|
| 414 | - Instant Client Package - Basic |
|---|
| 415 | - Instant Client Package - SDK |
|---|
| 416 | |
|---|
| 417 | In the following we are using RPM files for an installation on a Debian based system. |
|---|
| 418 | |
|---|
| 419 | First install the required packages ``alien`` and ``libaio1``:: |
|---|
| 420 | |
|---|
| 421 | sudo apt-get install alien libaio1 |
|---|
| 422 | |
|---|
| 423 | Install the two RPM packages:: |
|---|
| 424 | |
|---|
| 425 | sudo alien -i oracle-instantclient11.2-basic-11.2.0.1.0-1.i386.rpm |
|---|
| 426 | sudo alien -i oracle-instantclient11.2-devel-11.2.0.1.0-1.i386.rpm |
|---|
| 427 | |
|---|
| 428 | To add the installed libraries to the system search path, create the file |
|---|
| 429 | ``/etc/ld.so.conf.d/oracle.conf`` and insert the path to your installation, for example:: |
|---|
| 430 | |
|---|
| 431 | /usr/lib/oracle/11.2/client/lib/ |
|---|
| 432 | |
|---|
| 433 | Then run ``ldconfig`` to update the library cache:: |
|---|
| 434 | |
|---|
| 435 | sudo ldconfig |
|---|
| 436 | ldconfig -p | grep oracle |
|---|
| 437 | |
|---|
| 438 | The last command should print out the Oracle library files. |
|---|
| 439 | |
|---|
| 440 | Installation of cx_Oracle |
|---|
| 441 | """"""""""""""""""""""""" |
|---|
| 442 | |
|---|
| 443 | Installer files for various operating systems and Oracle versions can be found on the `cx_Oracle website |
|---|
| 444 | <http://cx-oracle.sourceforge.net/>`_. In the following we are building cx_Oracle from source. To do so, download |
|---|
| 445 | the source code archive from `cx_Oracle - Files <http://sourceforge.net/projects/cx-oracle/files/>`_. |
|---|
| 446 | |
|---|
| 447 | Before building cx_Oracle three environment variables have to be set:: |
|---|
| 448 | |
|---|
| 449 | export ORACLE_HOME=/usr/lib/oracle/11.2/client/ |
|---|
| 450 | export LD_LIBRARY_PATH=$ORACLE_HOME/lib |
|---|
| 451 | export PATH=$ORACLE_HOME/bin:$PATH |
|---|
| 452 | |
|---|
| 453 | Then start the setup inside your virtual environment:: |
|---|
| 454 | |
|---|
| 455 | (venv) $ python setup.py install |
|---|
| 456 | |
|---|
| 457 | To test if the installation was succesfull, start a Python interpreter and try to |
|---|
| 458 | import the cx_Oracle module:: |
|---|
| 459 | |
|---|
| 460 | (venv) $ python -i |
|---|
| 461 | >>> import cx_Oracle |
|---|
| 462 | >>> |
|---|
| 463 | |
|---|
| 464 | .. hint:: |
|---|
| 465 | |
|---|
| 466 | If you are using `Buildout <http://www.buildout.org/>`_ you may want to take a look at |
|---|
| 467 | the recipe `gocept.cxoracle <http://pypi.python.org/pypi/gocept.cxoracle>`_, which automatically |
|---|
| 468 | installs cx_Oracle and Oracle Instant Client. |
|---|
| 469 | |
|---|
| 470 | Configuration |
|---|
| 471 | ------------- |
|---|
| 472 | |
|---|
| 473 | When using cx_Oracle inside MapFish, the environment variables ``ORACLE_HOME`` and ``LD_LIBRARY`` have to be set |
|---|
| 474 | before the cx_Oracle module is used from SQLAlchemy. You can do this in the file ``config/environment.py`` before |
|---|
| 475 | the SQLAlchemy ``engine`` is created from the configuration:: |
|---|
| 476 | |
|---|
| 477 | def load_environment(global_conf, app_conf): |
|---|
| 478 | |
|---|
| 479 | # ... |
|---|
| 480 | |
|---|
| 481 | # Set the evironment variables required for cx_Oracle |
|---|
| 482 | os.environ['ORACLE_HOME'] = '/usr/lib/oracle/11.2/client/' |
|---|
| 483 | os.environ['LD_LIBRARY'] = '/usr/lib/oracle/11.2/client/lib' |
|---|
| 484 | |
|---|
| 485 | # Setup the SQLAlchemy database engine |
|---|
| 486 | engine = engine_from_config(config, 'sqlalchemy.') |
|---|
| 487 | init_model(engine) |
|---|
| 488 | |
|---|
| 489 | Then set the database connection string in your Pylons configuration file ``development.ini``:: |
|---|
| 490 | |
|---|
| 491 | sqlalchemy.url = oracle://www-data:www-data@localhost:1521/gis |
|---|
| 492 | |
|---|
| 493 | Notes about the Oracle dimension information array |
|---|
| 494 | -------------------------------------------------- |
|---|
| 495 | |
|---|
| 496 | Oracle requires a *Dimension Information Array (DIMINFO)* in its geometry metadata table |
|---|
| 497 | for every spatial column (see `Oracle® Spatial User's Guide and Reference: Geometry Metadata Views |
|---|
| 498 | <http://download.oracle.com/docs/cd/B12037_01/appdev.101/b10826/sdo_objrelschema.htm#i1001937>`_). |
|---|
| 499 | |
|---|
| 500 | If you are creating your tables with SQLAlchemy/GeoAlchemy (see :ref:`setup-app`), you will have to |
|---|
| 501 | specify a DIMINFO in your model files. GeoAlchemy then will make an entry in the view |
|---|
| 502 | ``USER_SDO_GEOM_METADATA`` (see also `Oracle® Spatial User's Guide and Reference: DIMINFO |
|---|
| 503 | <http://download.oracle.com/docs/cd/B12037_01/appdev.101/b10826/sdo_objrelschema.htm#i1010905>`_). |
|---|
| 504 | |
|---|
| 505 | Example definition (``model/places.py``):: |
|---|
| 506 | |
|---|
| 507 | from sqlalchemy import Column, types |
|---|
| 508 | from sqlalchemy.schema import Sequence |
|---|
| 509 | |
|---|
| 510 | from geoalchemy import GeometryColumn, Point, GeometryDDL |
|---|
| 511 | |
|---|
| 512 | from mapfish.sqlalchemygeom import GeometryTableMixIn |
|---|
| 513 | from mapfishsample.model.meta import engine, Base |
|---|
| 514 | |
|---|
| 515 | diminfo = "MDSYS.SDO_DIM_ARRAY("\ |
|---|
| 516 | "MDSYS.SDO_DIM_ELEMENT('LONGITUDE', -180, 180, 0.000000005),"\ |
|---|
| 517 | "MDSYS.SDO_DIM_ELEMENT('LATITUDE', -90, 90, 0.000000005)"\ |
|---|
| 518 | ")" |
|---|
| 519 | |
|---|
| 520 | class Place(Base, GeometryTableMixIn): |
|---|
| 521 | __tablename__ = 'places' |
|---|
| 522 | id = Column(types.Integer, Sequence('place_id_seq'), primary_key=True) |
|---|
| 523 | name = Column(types.String(40)) |
|---|
| 524 | |
|---|
| 525 | the_geom = GeometryColumn(Point(dimension=2, srid=4326, diminfo=diminfo)) |
|---|
| 526 | |
|---|
| 527 | GeometryDDL(Place.__table__) |
|---|
| 528 | |
|---|
| 529 | For Oracle MapFish in general uses the operator ``SDO_WITHIN_DISTANCE`` for spatial filter queries. |
|---|
| 530 | If the filter geometry (Lat/Lon, BBox or arbitrary geometry) uses a different SRID, the geometry column |
|---|
| 531 | has to be reprojected to this SRID. In this case the Oracle function ``SDO_GEOM.WITHIN_DISTANCE`` has to be |
|---|
| 532 | used which either requires dimension information arrays or a tolerance value. These parameters have to be |
|---|
| 533 | set on custom filters for the method ``index()`` inside the controller classes. |
|---|
| 534 | |
|---|
| 535 | Example (``controllers/places.py``):: |
|---|
| 536 | |
|---|
| 537 | class PlacesController(BaseController): |
|---|
| 538 | # .. |
|---|
| 539 | |
|---|
| 540 | def index(self, format='json'): |
|---|
| 541 | """GET /: return all features.""" |
|---|
| 542 | filter = create_default_filter(request, Place, additional_params={'tol': '0.005'}) |
|---|
| 543 | return self.protocol.read(request, filter=filter) |
|---|
| 544 | # .. |
|---|
| 545 | |
|---|
| 546 | The tolerance value will be passed to ``SDO_GEOM.WITHIN_DISTANCE``. Alternatively you can set |
|---|
| 547 | a DIMINFO for the reprojected geometry column and the filter query using the keywords ``dim1`` and |
|---|
| 548 | ``dim2``. |
|---|
| 549 | |
|---|
| 550 | Note that this tolerance is not the one used in the `MapFish Protocol |
|---|
| 551 | <../protocol.html>`_ to specify a distance in which features should be queried. |
|---|
| 552 | |
|---|
| 553 | .. hint:: |
|---|
| 554 | |
|---|
| 555 | More information about using Oracle can be found in the `GeoAlchemy documentation |
|---|
| 556 | <http://geoalchemy.org/usagenotes.html#notes-for-oracle>`_. |
|---|
| 557 | |
|---|
| 558 | Notes about using a tolerance value for MapFish Web Services in Oracle |
|---|
| 559 | ---------------------------------------------------------------------- |
|---|
| 560 | |
|---|
| 561 | Requests to a MapFish web service can contain a tolerance parameter, which specifies within which distance |
|---|
| 562 | features should be queried. Usually the unit of this value is the unit associated with the coordinate system |
|---|
| 563 | in use (for example degree for ``EPSG:4326``). But for geodetic coordinate systems (like ``EPSG:4326``) |
|---|
| 564 | Oracle uses meter as unit. You have to keep this in mind when developing applications for Oracle. |
|---|
| 565 | |
|---|
| 566 | If you want to use a different unit, you can set it as parameter in your controller files. This |
|---|
| 567 | parameter is passed to the database function call without further checks. |
|---|
| 568 | |
|---|
| 569 | Example (``controllers/places.py``):: |
|---|
| 570 | |
|---|
| 571 | # .. |
|---|
| 572 | |
|---|
| 573 | def index(self, format='json'): |
|---|
| 574 | """GET /: return all features.""" |
|---|
| 575 | filter = create_default_filter(request, Place, additional_params={'params': 'unit=KM'}) |
|---|
| 576 | return self.protocol.read(request, filter=filter) |
|---|
| 577 | |
|---|
| 578 | # .. |
|---|
| 579 | |
|---|
| 580 | Valid units are listed in the view ``SDO_DIST_UNITS``. |
|---|
| 581 | |
|---|
| 582 | Sperical Mercator (900913) |
|---|
| 583 | =========================== |
|---|
| 584 | |
|---|
| 585 | For many map tiles (including OpenStreetMap and Google Maps) `Sperical Mercator |
|---|
| 586 | <http://docs.openlayers.org/library/spherical_mercator.html>`_ (EPSG: 900913) is used as projection. For Spatialite and PostGIS |
|---|
| 587 | in releases prior to PostGIS 1.4, *Sperical Mercator* is not supported by default and you will receive |
|---|
| 588 | an error message like the following, when you try to work with geometries using *Sperical Mercator* as |
|---|
| 589 | spatial reference system (SRS):: |
|---|
| 590 | |
|---|
| 591 | (InternalError) AddToPROJ4SRSCache: Cannot find SRID (900913) in spatial_ref_sys [..] |
|---|
| 592 | |
|---|
| 593 | To enable support for *Sperical Mercator*, you first will have to update the library ``proj``, because on Ubuntu ``proj`` comes without datum shifting |
|---|
| 594 | files which are required for transformations with the *Sperical Mercator* projection. Run the following commands |
|---|
| 595 | to update your installation (see also `Notes on proj |
|---|
| 596 | <http://docs.djangoproject.com/en/dev/ref/contrib/gis/install/#id43>`_):: |
|---|
| 597 | |
|---|
| 598 | wget http://download.osgeo.org/proj/proj-datumgrid-1.4.tar.gz |
|---|
| 599 | mkdir nad |
|---|
| 600 | cd nad |
|---|
| 601 | tar xzf ../proj-datumgrid-1.4.tar.gz |
|---|
| 602 | nad2bin null < null.lla |
|---|
| 603 | sudo cp null /usr/share/proj |
|---|
| 604 | |
|---|
| 605 | Then for **PostGIS** run the following statements to insert the reference definition in PostGIS' ``spatial_ref_sys`` table:: |
|---|
| 606 | |
|---|
| 607 | sudo su postgres |
|---|
| 608 | psql gis |
|---|
| 609 | INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, srtext, proj4text) VALUES (900913, 'EPSG', 900913, 'PROJCS["unnamed",GEOGCS["unnamed ellipse",DATUM["unknown",SPHEROID["unnamed",6378137,0]], PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]], PROJECTION["Mercator_2SP"],PARAMETER["standard_parallel_1",0],PARAMETER["central_meridian",0],PARAMETER["false_easting",0], PARAMETER["false_northing",0],UNIT["Meter",1],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"]]', '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs'); |
|---|
| 610 | \q |
|---|
| 611 | exit |
|---|
| 612 | |
|---|
| 613 | The same can be done for **Spatialite**:: |
|---|
| 614 | |
|---|
| 615 | spatialite gis.sqlite |
|---|
| 616 | INSERT INTO spatial_ref_sys (srid, auth_name, auth_srid, ref_sys_name, proj4text) VALUES (900913, 'EPSG', 900913, 'Google Sperical Mercator', '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs'); |
|---|
| 617 | .quit |
|---|
| 618 | |
|---|
| 619 | Table mapping |
|---|
| 620 | ============= |
|---|
| 621 | |
|---|
| 622 | Declarative and non-declarative mapping |
|---|
| 623 | --------------------------------------- |
|---|
| 624 | |
|---|
| 625 | With SQLAlchemy table mappings can be configured either by defining a table and a class |
|---|
| 626 | separetly (non-declarative) or by doing this at once (declarative). MapFish supports both ways. |
|---|
| 627 | The following two examples show the mapping for a table ``spots``, one time as non-declarative and |
|---|
| 628 | one time as declarative mapping. |
|---|
| 629 | |
|---|
| 630 | **Non-declarative mapping**: |
|---|
| 631 | |
|---|
| 632 | .. code-block:: python |
|---|
| 633 | |
|---|
| 634 | from sqlalchemy import Column, Table, Integer, Numeric |
|---|
| 635 | from sqlalchemy.orm import mapper |
|---|
| 636 | |
|---|
| 637 | from geoalchemy import (Geometry, GeometryColumn, |
|---|
| 638 | GeometryDDL, GeometryExtensionColumn) |
|---|
| 639 | |
|---|
| 640 | from mapfish.sqlalchemygeom import GeometryTableMixIn |
|---|
| 641 | |
|---|
| 642 | from mapfishsample.model.meta import metadata |
|---|
| 643 | |
|---|
| 644 | # table definition |
|---|
| 645 | spots_table = Table('spots', metadata, |
|---|
| 646 | Column('spot_id', Integer, primary_key=True), |
|---|
| 647 | Column('spot_height', Numeric(asdecimal=False)), |
|---|
| 648 | GeometryExtensionColumn('spot_location', Geometry(2))) |
|---|
| 649 | |
|---|
| 650 | # class definition |
|---|
| 651 | class Spot(GeometryTableMixIn): |
|---|
| 652 | __table__ = spots_table |
|---|
| 653 | |
|---|
| 654 | def __init__(self, spot_id=None, spot_height=None, spot_location=None): |
|---|
| 655 | self.spot_id = spot_id |
|---|
| 656 | self.spot_height = spot_height |
|---|
| 657 | self.spot_location = spot_location |
|---|
| 658 | |
|---|
| 659 | # set up the mapping between table and class |
|---|
| 660 | mapper(Spot, spots_table, properties={ |
|---|
| 661 | 'spot_location': GeometryColumn(spots_table.c.spot_location, |
|---|
| 662 | comparator=PGComparator)}) |
|---|
| 663 | |
|---|
| 664 | # register table for DDL extension, so that it can be created from SQLAlchemy |
|---|
| 665 | GeometryDDL(spots_table) |
|---|
| 666 | |
|---|
| 667 | |
|---|
| 668 | **Declarative mapping**: |
|---|
| 669 | |
|---|
| 670 | .. code-block:: python |
|---|
| 671 | |
|---|
| 672 | from sqlalchemy import Column, types |
|---|
| 673 | |
|---|
| 674 | from geoalchemy import GeometryColumn, Geometry |
|---|
| 675 | |
|---|
| 676 | from mapfish.sqlalchemygeom import GeometryTableMixIn |
|---|
| 677 | from mapfishsample.model.meta import engine, Base |
|---|
| 678 | |
|---|
| 679 | class Spot(Base, GeometryTableMixIn): |
|---|
| 680 | __tablename__ = 'spots' |
|---|
| 681 | |
|---|
| 682 | spot_id = Column(Integer, primary_key=True) |
|---|
| 683 | spot_height = Column(Numeric(asdecimal=False)) |
|---|
| 684 | spot_location = GeometryColumn(Point(2), comparator=PGComparator) |
|---|
| 685 | |
|---|
| 686 | GeometryDDL(Spot.__table__) |
|---|
| 687 | |
|---|
| 688 | .. hint:: |
|---|
| 689 | |
|---|
| 690 | See also `Creating Table, Class and Mapper All at Once Declaratively |
|---|
| 691 | <http://www.sqlalchemy.org/docs/ormtutorial.html#creating-table-class-and-mapper-all-at-once-declaratively>`_. |
|---|
| 692 | |
|---|
| 693 | Geometry column properties |
|---|
| 694 | -------------------------- |
|---|
| 695 | |
|---|
| 696 | When using ``paster mf-layer`` or ``paster mf-model``, MapFish creates a default configuration |
|---|
| 697 | for the geometry column of your table. You may want to customize this configuration to your needs. |
|---|
| 698 | |
|---|
| 699 | **Example configuration for** ``model/spots.py``: |
|---|
| 700 | |
|---|
| 701 | .. code-block:: python |
|---|
| 702 | |
|---|
| 703 | # [..] |
|---|
| 704 | spot_location = GeometryColumn( |
|---|
| 705 | Point(dimension=2, srid=4326, spatial_index=True), |
|---|
| 706 | comparator=PGComparator, |
|---|
| 707 | nullable=False) |
|---|
| 708 | # [..] |
|---|
| 709 | |
|---|
| 710 | ``dimension=2`` |
|---|
| 711 | |
|---|
| 712 | The dimension of the geometry (default: 2). |
|---|
| 713 | |
|---|
| 714 | ``srid=4326`` |
|---|
| 715 | |
|---|
| 716 | The spatial reference system (SRS) of the geometry column as EPSG code (default: 4326). |
|---|
| 717 | |
|---|
| 718 | ``spatial_index=True`` |
|---|
| 719 | |
|---|
| 720 | Indicates if a *spatial index* is created for the geometry column (default: True). |
|---|
| 721 | |
|---|
| 722 | .. hint:: |
|---|
| 723 | |
|---|
| 724 | Spatialite does not automatically make use of the spatial index when executing queries, you |
|---|
| 725 | explicitly have to access the spatial index in your queries, see `Spatial Index: using SQLite's R*Tree |
|---|
| 726 | <http://www.gaia-gis.it/spatialite/spatialite-tutorial-2.3.1.html#t8>`_. |
|---|
| 727 | |
|---|
| 728 | ``comparator=PGComparator`` |
|---|
| 729 | |
|---|
| 730 | You only have to set this option, when you want to use a database specific function (like `AsKML` in PostGIS) on |
|---|
| 731 | a geometry column in a SQLAlchemy query (for example ``session.query(Spot).filter(Spot.geom.kml == '..'``). Following |
|---|
| 732 | comparators are available: |
|---|
| 733 | |
|---|
| 734 | * PostGIS: *geoalchemy.postgis.PGComparator* |
|---|
| 735 | * MySQL: *geoalchemy.mysql.MySQLComparator* |
|---|
| 736 | * Spatialite: *geoalchemy.spatialite.SQLiteComparator* |
|---|
| 737 | * Oracle: *geoalchemy.oracle.OracleComparator* |
|---|
| 738 | |
|---|
| 739 | ``nullable=False`` |
|---|
| 740 | |
|---|
| 741 | Indicates if ``null`` values can be inserted into the geometry column (default: True). |
|---|
| 742 | |
|---|
| 743 | .. note:: |
|---|
| 744 | |
|---|
| 745 | When using MySQL with a spatial index, the parameter ``nullable`` is ignored, because MySQL |
|---|
| 746 | requires a ``NOT NULL`` constraint for spatial indexed columns. |
|---|
| 747 | |
|---|
| 748 | |
|---|
| 749 | .. _setup-app: |
|---|
| 750 | |
|---|
| 751 | Using 'paster setup-app' to create your database tables |
|---|
| 752 | ========================================================== |
|---|
| 753 | |
|---|
| 754 | When setting up a Pylons application, you often have to create database tables to run the |
|---|
| 755 | application. SQLAlchemy/GeoAlchemy can take over that task for you, so that all your tables |
|---|
| 756 | are created just by calling ``paster setup-app config.ini``. |
|---|
| 757 | |
|---|
| 758 | The following steps describe how to configure your application. |
|---|
| 759 | |
|---|
| 760 | #. **Table mapping** |
|---|
| 761 | |
|---|
| 762 | All columns that you want to be created for a table, must be enlisted in the table |
|---|
| 763 | definition. |
|---|
| 764 | |
|---|
| 765 | *Example:* ``model/Point.py`` |
|---|
| 766 | |
|---|
| 767 | .. code-block:: python |
|---|
| 768 | |
|---|
| 769 | from sqlalchemy import Column, types |
|---|
| 770 | |
|---|
| 771 | from geoalchemy import GeometryColumn, Point, GeometryDDL |
|---|
| 772 | |
|---|
| 773 | from mapfish.sqlalchemygeom import GeometryTableMixIn |
|---|
| 774 | from mapfishsample.model.meta import metadata, Base |
|---|
| 775 | |
|---|
| 776 | |
|---|
| 777 | class Point(Base, GeometryTableMixIn): |
|---|
| 778 | __tablename__ = 'points' |
|---|
| 779 | |
|---|
| 780 | id = Column(types.Integer, primary_key=True) |
|---|
| 781 | name = Column(types.String(30), default = 'foo') |
|---|
| 782 | the_geom = GeometryColumn(Point(dimension=2, srid=4326)) |
|---|
| 783 | |
|---|
| 784 | GeometryDDL(Point.__table__) |
|---|
| 785 | |
|---|
| 786 | Note the last line ``GeometryDDL(Point.__table__)``, this makes sure that |
|---|
| 787 | GeoAlchemy creates the geometry field of the table. |
|---|
| 788 | |
|---|
| 789 | #. **websetup.py** |
|---|
| 790 | |
|---|
| 791 | When calling ``paster setup-app config.ini``, the method ``setup_app()`` inside the |
|---|
| 792 | file ``[your_app]/websetup.py`` is executed. By default the method ``setup_app()`` |
|---|
| 793 | already contains the command ``metadata.create_all()`` that creates the tables. You |
|---|
| 794 | just have to import your model classes. |
|---|
| 795 | |
|---|
| 796 | *Example:* ``websetup.py`` |
|---|
| 797 | |
|---|
| 798 | .. code-block:: python |
|---|
| 799 | |
|---|
| 800 | """Setup the MapFishSample application""" |
|---|
| 801 | import logging |
|---|
| 802 | |
|---|
| 803 | from mapfishsample.config.environment import load_environment |
|---|
| 804 | from mapfishsample.model import meta |
|---|
| 805 | |
|---|
| 806 | # Import the model classes you want to create the tables for |
|---|
| 807 | from mapfishsample.model import points |
|---|
| 808 | |
|---|
| 809 | log = logging.getLogger(__name__) |
|---|
| 810 | |
|---|
| 811 | def setup_app(command, conf, vars): |
|---|
| 812 | """Place any commands to setup mapfishsample here""" |
|---|
| 813 | load_environment(conf.global_conf, conf.local_conf) |
|---|
| 814 | |
|---|
| 815 | # Create the tables if they don't already exist |
|---|
| 816 | meta.metadata.create_all(bind=meta.engine) |
|---|
| 817 | |
|---|
| 818 | #. **paster setup-app** |
|---|
| 819 | |
|---|
| 820 | Finally to setup your application, run the following command inside the virtual environment: |
|---|
| 821 | |
|---|
| 822 | .. code-block:: bash |
|---|
| 823 | |
|---|
| 824 | (venv) $ paster setup-app [your_config].ini |
|---|