[[TOC(GeoDjangoBackground, GeoDjango, GeoDjangoModelAPI, GeoDjangoDatabaseAPI)]] The [http://code.djangoproject.com/browser/django/branches/gis GIS] branch intends to be a world-class geographic web framework. Our goal is to make it as easy as possible to build GIS web applications and harness the power of spatially enabled data. ''News:'' The project has been [http://www.foss4g2007.org/presentations/view.php?abstract_id=222 submitted to FOSS4G 2007]. If you want to see us there in September, use the [http://www.foss4g2007.org/presentations/review/ community review] to show your interest! '''Note:''' The documentation has been re-factored into several pages. See the table of contents on the right for a complete listing of topics. Other GeoDjango pages include: * [wiki:GeoDjangoBackground Background Information] * [wiki:GeoDjangoModelAPI Model API] * [wiki:GeoDjangoDatabaseAPI Database API] = Roadmap = '''Note:''' In order to minimize confusion, please don't modify the official roadmap below. If you have a suggestion, place it in the [wiki:GeoDjango#Suggestions suggestion section] or ask your question in the [wiki:GeoDjango#FAQ FAQ]. If your request is urgent, submit a ticket requesting your feature (make sure to specify the component as 'GIS'). Thanks for your cooperation! == Phase 1 == * Create Geometry-enabled fields and manager. Status: complete as of r4788. * Allow for Geometry-enabled queries. Status: complete as of r4788. == Phase 2 == * '''Pending''' * Distance queries, calculations, and related utilities. * Support for a mapping framework (e.g. Google Maps/Earth, Yahoo Maps, MS Live, etc.) * Admin fields and forms (WKT field currently as of r4884, but we want widgets to view and manipulate geographic objects). * WMS views. * Add as much from the PostGIS API as possible. * '''Complete''' * PostGIS indexing capability. * As of r5008, added a {{{ctypes}}} interface for [http://geos.refractions.net/ GEOS] in [source:django/branches/gis/django/contrib/gis/gdal django.contrib.gis.geos]. * {{{GEOSGeometry}}}: Wraps [http://geos.refractions.net/ro/doxygen_docs/html/classgeos_1_1geom_1_1Geometry.html GEOS geometries], may be accessed with an [wiki:GeoDjangoDatabaseAPI#ExtraInstanceMethods extra instance method] (''e.g.'', {{{z.get_poly_geos()}}}). * As of r5397, added a {{{ctypes}}} interface for [http://www.gdal.org/ogr/ogr_arch.html GDAL/OGR] in [source:django/branches/gis/django/contrib/gis/gdal django.contrib.gis.gdal]. * {{{OGRGeometry}}}: Wraps [http://www.gdal.org/ogr/classOGRGeometry.html OGR geometries], may be accessed with an extra instance method (''e.g.'', {{{z.get_poly_ogr()}}}). * {{{SpatialReference}}}: Wraps [http://www.gdal.org/ogr/classOGRSpatialReference.html OGR Spatial Reference] objects, may be used to transform OGR geometries. * {{{DataSource}}}: Wraps [http://www.gdal.org/ogr/classOGRDataSource.html OGR Data Source] objects, may be used to explore GDAL-supported data sources * As of r5529, there are utilities for importing vector data (''e.g.'', SHP files) directly into GeoDjango models. * The [source:django/branches/gis/django/contrib/gis/utils/LayerMapping.py LayerMapping] class will import vector data from GDAL-supported data sources. This is still 'beta', and requires installation of the [wiki:GeoDjango#GDAL GDAL library]. == Phase 3 == * Support MySQL databases. * Geocoding framework. = Implementation = == Design Issues == * Client JS/Flash framework, ''i.e.'', do we want to support OpenLayers, the Google Maps API, the Yahoo API? * So far, Google Maps looks the most promising for being supported first (people are familiar with it, and it's more stable than open layers). * [http://developer.yahoo.com/maps/ Yahoo!] has a really slick flash interface, I'd like to support this eventually. * [http://www.openlayers.org/ OpenLayers] supports WMS/WFS/tiles as well as Google, MSVE, and Yahoo layers. It is very flexible and open(!!). ''(Rob Coup)'' * Mapping Framework (generating custom tiles, layers, labels, etc.) * [http://www.mapnik.org/ Mapnik] is modern, but very early on in development and ''completely'' lacks documentation. However, the code is elegant and clean, and it was designed for integration with Python -- we're leaning towards this right now. * [http://mapserver.gis.umn.edu/ Mapserver] has been around for a while, strong backing in the community (e.g. native support in [http://qgis.org/ QGIS]). Even with documentation, the code looks less inviting than Mapnik (all in C); also has archaic text-based configuration files (pre-dating markup languages). * GEOS * '''Update:''' As of r5008, GeoDjango has its own GEOS interface (via {{{ctypes}}}) * GEOS is no longer maintained by Sean Gillies. ''See'' Sean Gillies, ''[http://zcologia.com/news/150/geometries-for-python/ Geometries for Python]'' (blog post explaining rationale for abandoning GEOS support); ''see also'' Sean's message on the [http://geos.refractions.net/pipermail/geos-devel/2007-March/002851.html GEOS-Devel Mailing List] (Mar. 5, 2007). * WMS Server * I'm not satisfied with any of the current WMS/WFS implementations. One implemented in Django would be desirable, e.g., {{{django.contrib.gis.wms}}}. Thoughts anyone? (OWSLib looks good, see below) == Collaboration == * PCL (Python Cartographic Library), now part of [http://www.gispython.org/ GIS Python], has done a lot of good work already. Let's apply the DRY principle. Strong opportunities for collaboration with regards to: * Mapping framework * WMS/WMF Framework -- '''[http://trac.gispython.org/projects/PCL/browser/OWSLib/trunk OWSLib]''' looks excellent for this (BSD licensed and has unit tests!) * Utilities * Database representation ideas * GEOS support, [http://zcologia.com/news/ Sean Gilles] (of PCL) was the maintainer of the old SWIG bindings, and is working on [http://trac.gispython.org/projects/PCL/wiki/ShapeLy ShapeLy], a GeoDjango-inspired GEOS ctypes interface. * [http://code.google.com/p/django-coordinatesfield/ CoordinatesField]. * Jannis Leidel has already come up with a way to manipulate points in the admin interface, BSD licensed. * [http://exogen.case.edu/projects/geopy/ geopy] * Brian Beck has written a good foundation for geocoding and distance calculations, BSD licensed. == Suggestions == * Decide what to do about "invalid" shape files, for example, float SHP field with ' ' value. * Geo field introspection. = FAQ = * Place your questions '''here'''. * '''Q:''' When dealing with points (say, degrees) from, do they need to be converted to be useful on the back-end data, assuming -that- data is in degrees? Is it enough to have the same datum and origin? (Reading the intro above is likely to answer the question.) * My (JDunck) reading indicates yes. Given the same coordinate system (i.e. datum, origin, and axes), degrees are useful without conversion. * '''Q:''' Can this implementation work with [http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html MySQL spatial-extensions]. If not, it's planned? * No. It is (now) planned, ''see'' Phase 3 below. From the last time I (jbronn) checked, MySQL's spatial capabilities have improved. However, we're going to focus our efforts on PostGIS until things are worked out a bit more. As a spatial database PostGIS it is more standards compliant (OpenGIS consortium), more widely used, and has more features (e.g. coordinate transformation, {{{geometry_columns}}} and {{{spatial_ref_sys}}} tables). It is definitely something I would want to implement in the future since I do ''like'' MySQL. * '''Q:''' Is this going to be a WMS Server/WMS Client/Both? OWSLib is just a WMS Client from what I have seen (from ruckc) * WMS Server first, client capability a possibility in certain situations (i.e. you want to cache data from another WMS server). Yes, OWSLib is a client, but it contains code for validating the correct parameters to send to a WMS server, thus it can be adapted into a Django view that validates whether the proper WMS parameters were given. Mapnik has an {{{ogcserver}}} module that can parse the correct parameters for WMS 1.1.1 and 1.3.0, however since it is licensed under the LGPL it cannot be easily incorporated into this branch (unlike OWSLib). * '''Q:''' Per [http://groups.google.com/group/django-developers/browse_thread/thread/9f6c70864bfa7f2e/ this discussion] in {{{django-developers}}}, "I can do spatial queries if they are directly between two models with polygon fields but I can't seem to get at the spatial queries through foreign keys." * Geographic queries require {{{GeoManager}}}, even if the model does not have a geographic field itself (in the case of a foreign key to a geo-field). The reply in the discussion gives detail into why. * '''Q:''' Why are the OGRGeometry methods {{{transform}}} and {{{transform_to}}} separate? * Because these map to the separate OGR routines [http://www.gdal.org/ogr/ogr__api_8h.html#59a5b3f954b11cfbf6e78807c28d6090 OGR_G_Transform] and [http://www.gdal.org/ogr/ogr__api_8h.html#43af4c2127cea0a5059692a62c0feb63 OGR_G_TransformTo]. Specifically, the {{{transform}}} routine takes a CoordTransform object as a parameter, whereas the {{{transform_to}}} routine takes a SpatialReference object. The {{{transform_to}}} "function requires internal creation and initialization of [a CoordTransform] object [and] it is significantly more expensive to use this function to transform many geometries than it is to create the [CoordTransform object] in advance, and call transform() with that transformation. This function exists primarily for convenience when only transforming a single geometry." = Example = == Geographic Models == Here is an example of how the model API currently works (assume this example is in geo_app/models.py): {{{ #!python from django.contrib.gis.db import models class District(models.Model, models.GeoMixin): name = models.CharField(maxlength=35) num = models.IntegerField() poly = models.PolygonField() objects = models.GeoManager() class School(models.Model, models.GeoMixin): name = models.CharField(maxlength=35) point = models.PointField() objects = models.GeoManager() }}} '''Notes''': The {{{GeoMixin}}} class allows for [wiki:GeoDjangoDatabaseAPI#ExtraInstanceMethods extra instance methods]. By default, a GiST index will be created for the School {{{PointField}}}s fields. This behavior can be turned off by using {{{models.PointField(index=False)}}}. == Using syncdb == Use the {{{manage.py}}} to invoke {{{syncdb}}} like you normally would: {{{ #!sql $ python manage.py sqlall geo_app BEGIN; CREATE TABLE "geo_app_school" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(35) NOT NULL ); CREATE TABLE "geo_app_district" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(35) NOT NULL, "num" integer NOT NULL ); SELECT AddGeometryColumn('geo_app_school', 'point', 4326, 'POINT', 2); CREATE INDEX "geo_app_school_point_id" ON "geo_app_school" USING GIST ( "point" GIST_GEOMETRY_OPS ); SELECT AddGeometryColumn('geo_app_district', 'poly', 4326, 'POLYGON', 2); CREATE INDEX "geo_app_district_poly_id" ON "geo_app_district" USING GIST ( "poly" GIST_GEOMETRY_OPS ); COMMIT; $ python manage.py syncdb geo_app }}} '''Note:''' The geometry columns are created outside of the {{{CREATE TABLE}}} statements by the {{{AddGeometryColumn}}}. This is done according to the OpenGIS specfication. * ''See'' Open GIS Consortium, Inc., ''[http://www.opengis.org/docs/99-049.pdf OpenGIS Simple Feature Specification For SQL]'', Document 99-049 (May 5, 1999), at Ch. 2.3.8 (Geometry Values and Spatial Reference Systems, pg. 39). == Spatial Queries == After a geographic model has been created, the PostGIS additions to the API may be used. Geographic queries are done normally by using {{{filter()}}} and {{{exclude()}}} on geometry-enabled models using geographic lookup types (''see'' the [wiki:GeoDjangoDatabaseAPI Database API] for lookup types). In the following example, the {{{bbcontains}}} lookup type is used which is the same as the PostGIS {{{&&}}} operator. It looks to see if the ''bounding box'' of the polygon contains the specific point. The next example uses the PostGIS {{{Contains()}}} function, which calls GEOS library to test if the ''polygon'' actually contains the specific point, not just the bounding box. {{{ #!python >>> from geo_app.models import District, School >>> qs1 = District.objects.filter(poly__bbcontains='POINT(-95.362293 29.756539)') >>> qs2 = District.objects.filter(poly__contains='POINT(-95.362293 29.756539)') }}} Both spatial queries and normal queries using {{{filter()}}} may be used in the same query. For example, the following query set will only show school districts that have 'Houston' in their name and contain the given point within their polygon boundary: {{{ #!python >>> qs = District.objects.filter(name__contains='Houston').filter(poly__contains='POINT(-95.362293 29.756539)') }}} Or combine both the bounding box routines (less accurate, fast) with the GEOS routines (most accurate, slower) to get a query that is both fast and accurate: {{{ #!python >>> qs = District.objects.filter(poly__bbcontains='POINT(-95.362293 29.756539)').filter(poly__contains='POINT(-95.362293 29.756539)') }}} = Installation = Installation of the GeoDjango module will also require the installation of existing open source geographic libraries and a spatial database (currently only PostGIS). This section will describe the installation process for these libraries. Initially, these instructions will pertain only to a Linux platform (particularly Debian or Ubuntu). Mac & Windows support will be considered later; however, these instructions will most likely work through the Mac shell. == Python & PostgreSQL == * '''Python''' * ''Required:'' Python 2.4 is required because of heavy use of 2.4 decorator syntax (''e.g.'' {{{@property}}}). The {{{ctypes}}} module needs to be installed as well. * ''Recommended:'' Python 2.5 is recommended because the {{{ctypes}}} module comes included. [http://www.python.org/download/releases/2.5.1/ Python 2.5.1] is the current latest. * '''PostgreSQL''' * ''Recommended:'' PostgreSQL 8.X * We are currently using v8.1 of PostgreSQL, and know of no problems with 8.2 * On Ubuntu Feisty, you'll need the apt packages {{{postgresql-server-dev-8.x}}} (the development headers are needed for PostGIS compilation) and {{{postgresql-8.x}}}. == Django == * GeoDjango exists in the {{{gis}}} branch from SVN: {{{ $ svn co http://code.djangoproject.com/svn/django/branches/gis django_gis $ ln -s django_gis/django /path/to/site-packages/django }}} == GEOS == * Latest [http://geos.refractions.net/ GEOS] version is 3.0.0RC4 * '''Update:''' As of r5008, you do ''not'' need to enable the Python bindings because GeoDjango has its own GEOS {{{ctypes}}} wrapper. * {{{ctypes}}} comes standard with Python 2.5. If you run Python 2.4, {{{ctypes}}} may be [http://sourceforge.net/project/showfiles.php?group_id=71702&package_id=71318 downloaded here] * Configure, make, and install. {{{ $ ./configure $ make # make install }}} == PROJ.4 == * Latest [http://proj.maptools.org/ PROJ.4] version is 4.5.0 * First, download the PROJ [ftp://ftp.remotesensing.org/proj/proj-datumgrid-1.3.tar.gz datum shifting files]. These will come in handy for coordinate transformations when other programs (like Mapserver or Mapnik) are not able to cope with EPSG transformations (I learned the hard way). Untar/unzip these in the {{{nad}}} subdirectory of the PROJ source. For example, if PROJ was unzipped in a directory named {{{proj}}}, then untar these files in {{{proj/nad}}}. Do this '''before''' you do the configure/make/install dance. * ''See'' [http://remotesensing.org/proj/faq.html PROJ FAQ]; ''see also'' [http://mapserver.gis.umn.edu/data2/wilma/mapserver-users/0301/msg00541.html Frank Warmerdam's reply to a Mapserver question]. * Next, configure, make and install. {{{ $ ./configure $ make # make install }}} == PostGIS == * Latest [http://postgis.refractions.net/download/ PostGIS] version is 1.2.1 * First build & install PostGIS. {{{ $ ./configure --with-geos --with-proj $ make # make install }}} * Next, create a role and database for your application, and allow it to access PostGIS functionality: {{{ # su - postgres $ psql postgres=# CREATE ROLE LOGIN; postgres=# \q $ createdb -O $ createlang plpgsql $ psql -d -f /usr/local/share/lwpostgis.sql $ psql -d -f /usr/local/share/spatial_ref_sys.sql $ psql =# GRANT SELECT, UPDATE, INSERT, DELETE ON geometry_columns TO ; =# GRANT SELECT ON spatial_ref_sys TO ; }}} * Finally, update your {{{settings.py}}} to reflect the name and user for the spatially enabled database. So far, we only plan to support the psycopg2 backend, thus: {{{DATABASE_ENGINE='postgresql_psycopg2'}}}. == GDAL == * ''Highly Recommended'': Some features (e.g. a large number of {{{SpatialRefSys}}} model routines) require GDAL, but it is not necessary for core functionality (e.g. spatial queries). * GDAL/OGR includes useful for coordinate transformations and reading/writing ''both'' vector (e.g. SHP) and raster (e.g. GeoTIFF) geographic data. * For example, the following command will convert your SHP file into [http://en.wikipedia.org/wiki/WGS84 WGS84] (standard lat/lon). Then you can import directly into your database using {{{shp2pgsql}}} (utility from PostGIS): {{{ ogr2ogr -t_srs WGS84 output.shp input.shp }}} * Latest [http://www.gdal.org/download.html GDAL] version is 1.4.2. Configure with GEOS then make (use {{{gmake}}} on Solaris platforms) and install: {{{ $ ./configure --with-geos $ make # make install }}} * As of r5397 there's a {{{ctypes}}} layer for GDAL/OGR, no additional Python bindings are needed. * If you still want to use the GDAL Python API for your own applications, then the following configuration flags: * {{{--with-python}}} {{{--without-ngpython}}}: the deprecated, but stable API. * {{{--without-python}}} {{{--with-ngpython}}}: the "next-generation" SWIG-based bindings -- used to problematic for Python 2.5 users, but the GDAL team has solved a lot of these issues in 1.4.2. * ''See generally'' [http://trac.osgeo.org/gdal/wiki/GdalOgrInPython GDAL/OGR In Python] on the GDAL trac wiki. == Windows == Though GeoDjango is not yet "officially" supported for Windows (due to documentation, see #4397), our ctypes interfaces have made compatibility with Windows 2000/XP a reality. The developer uses binary libraries from the following open-source projects (for Windows): * [http://www.postgis.org/news/20070319/ PostGIS 1.2.1 Windows Technology Preview]: Installs PostGIS 1.2.1 on Windows, and includes GEOS 3.0.0RC4 and proj libraries as well. * Copy {{{libgeos-3-0-0rc4.dll}}}, {{{libgeos_c-1.dll}}}, and {{{libproj.dll}}} to your Python directory (''e.g.'', {{{C:\Python25}}}) * [http://blog.qgis.org/?q=node/71 QGIS Windows 0.8.1 Release Candidate 1]: Installs QGIS, an open-source desktop application for GIS, similar to ArcView. Includes GDAL and its own proj libraries (more documentation forthcoming).