<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang=""> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>GeoDjango Tutorial — Django 1.8.19 documentation</title> <link rel="stylesheet" href="../../../_static/default.css" type="text/css" /> <link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" /> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT: '../../../', VERSION: '1.8.19', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="../../../_static/jquery.js"></script> <script type="text/javascript" src="../../../_static/underscore.js"></script> <script type="text/javascript" src="../../../_static/doctools.js"></script> <link rel="index" title="Index" href="../../../genindex.html" /> <link rel="search" title="Search" href="../../../search.html" /> <link rel="top" title="Django 1.8.19 documentation" href="../../../contents.html" /> <link rel="up" title="GeoDjango" href="index.html" /> <link rel="next" title="GeoDjango Installation" href="install/index.html" /> <link rel="prev" title="GeoDjango" href="index.html" /> <script type="text/javascript" src="../../../templatebuiltins.js"></script> <script type="text/javascript"> (function($) { if (!django_template_builtins) { // templatebuiltins.js missing, do nothing. return; } $(document).ready(function() { // Hyperlink Django template tags and filters var base = "../../templates/builtins.html"; if (base == "#") { // Special case for builtins.html itself base = ""; } // Tags are keywords, class '.k' $("div.highlight\\-html\\+django span.k").each(function(i, elem) { var tagname = $(elem).text(); if ($.inArray(tagname, django_template_builtins.ttags) != -1) { var fragment = tagname.replace(/_/, '-'); $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>"); } }); // Filters are functions, class '.nf' $("div.highlight\\-html\\+django span.nf").each(function(i, elem) { var filtername = $(elem).text(); if ($.inArray(filtername, django_template_builtins.tfilters) != -1) { var fragment = filtername.replace(/_/, '-'); $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>"); } }); }); })(jQuery); </script> </head> <body role="document"> <div class="document"> <div id="custom-doc" class="yui-t6"> <div id="hd"> <h1><a href="../../../index.html">Django 1.8.19 documentation</a></h1> <div id="global-nav"> <a title="Home page" href="../../../index.html">Home</a> | <a title="Table of contents" href="../../../contents.html">Table of contents</a> | <a title="Global index" href="../../../genindex.html">Index</a> | <a title="Module index" href="../../../py-modindex.html">Modules</a> </div> <div class="nav"> « <a href="index.html" title="GeoDjango">previous</a> | <a href="../../index.html" title="API Reference" accesskey="U">up</a> | <a href="install/index.html" title="GeoDjango Installation">next</a> »</div> </div> <div id="bd"> <div id="yui-main"> <div class="yui-b"> <div class="yui-g" id="ref-contrib-gis-tutorial"> <div class="section" id="s-geodjango-tutorial"> <span id="geodjango-tutorial"></span><h1>GeoDjango Tutorial<a class="headerlink" href="#geodjango-tutorial" title="Permalink to this headline">¶</a></h1> <div class="section" id="s-introduction"> <span id="introduction"></span><h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2> <p>GeoDjango is an included contrib module for Django that turns it into a world-class geographic Web framework. GeoDjango strives to make it as simple as possible to create geographic Web applications, like location-based services. Its features include:</p> <ul class="simple"> <li>Django model fields for <a class="reference external" href="http://www.opengeospatial.org/">OGC</a> geometries.</li> <li>Extensions to Django’s ORM for querying and manipulating spatial data.</li> <li>Loosely-coupled, high-level Python interfaces for GIS geometry operations and data formats.</li> <li>Editing geometry fields from the admin.</li> </ul> <p>This tutorial assumes familiarity with Django; thus, if you’re brand new to Django, please read through the <a class="reference internal" href="../../../intro/tutorial01.html"><span class="doc">regular tutorial</span></a> to familiarize yourself with Django first.</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">GeoDjango has additional requirements beyond what Django requires – please consult the <a class="reference internal" href="install/index.html"><span class="doc">installation documentation</span></a> for more details.</p> </div> <p>This tutorial will guide you through the creation of a geographic web application for viewing the <a class="reference external" href="http://thematicmapping.org/downloads/world_borders.php">world borders</a>. <a class="footnote-reference" href="#id10" id="id1">[1]</a> Some of the code used in this tutorial is taken from and/or inspired by the <a class="reference external" href="http://code.google.com/p/geodjango-basic-apps/">GeoDjango basic apps</a> project. <a class="footnote-reference" href="#id11" id="id2">[2]</a></p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">Proceed through the tutorial sections sequentially for step-by-step instructions.</p> </div> </div> <div class="section" id="s-setting-up"> <span id="setting-up"></span><h2>Setting Up<a class="headerlink" href="#setting-up" title="Permalink to this headline">¶</a></h2> <div class="section" id="s-create-a-spatial-database"> <span id="create-a-spatial-database"></span><h3>Create a Spatial Database<a class="headerlink" href="#create-a-spatial-database" title="Permalink to this headline">¶</a></h3> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">MySQL and Oracle users can skip this section because spatial types are already built into the database.</p> </div> <p>First, create a spatial database for your project.</p> <p>If you are using PostGIS, create the database from the <a class="reference internal" href="install/postgis.html#spatialdb-template"><span class="std std-ref">spatial database template</span></a>:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> createdb -T template_postgis geodjango </pre></div> </div> <div class="admonition note"> <p class="first admonition-title">Note</p> <p>This command must be issued by a database user with enough privileges to create a database. To create a user with <code class="docutils literal"><span class="pre">CREATE</span> <span class="pre">DATABASE</span></code> privileges in PostgreSQL, use the following commands:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> sudo su - postgres <span class="gp">$</span> createuser --createdb geo <span class="gp">$</span> <span class="nb">exit</span> </pre></div> </div> <p class="last">Replace <code class="docutils literal"><span class="pre">geo</span></code> with your Postgres database user’s username. (In PostgreSQL, this user will also be an OS-level user.)</p> </div> <p>If you are using SQLite and SpatiaLite, consult the instructions on how to create a <a class="reference internal" href="install/spatialite.html#create-spatialite-db"><span class="std std-ref">SpatiaLite database</span></a>.</p> </div> <div class="section" id="s-create-a-new-project"> <span id="create-a-new-project"></span><h3>Create a New Project<a class="headerlink" href="#create-a-new-project" title="Permalink to this headline">¶</a></h3> <p>Use the standard <code class="docutils literal"><span class="pre">django-admin</span></code> script to create a project called <code class="docutils literal"><span class="pre">geodjango</span></code>:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> django-admin startproject geodjango </pre></div> </div> <p>This will initialize a new project. Now, create a <code class="docutils literal"><span class="pre">world</span></code> Django application within the <code class="docutils literal"><span class="pre">geodjango</span></code> project:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> <span class="nb">cd</span> geodjango <span class="gp">$</span> python manage.py startapp world </pre></div> </div> </div> <div class="section" id="s-configure-settings-py"> <span id="configure-settings-py"></span><h3>Configure <code class="docutils literal"><span class="pre">settings.py</span></code><a class="headerlink" href="#configure-settings-py" title="Permalink to this headline">¶</a></h3> <p>The <code class="docutils literal"><span class="pre">geodjango</span></code> project settings are stored in the <code class="docutils literal"><span class="pre">geodjango/settings.py</span></code> file. Edit the database connection settings to match your setup:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">DATABASES</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">'default'</span><span class="p">:</span> <span class="p">{</span> <span class="s1">'ENGINE'</span><span class="p">:</span> <span class="s1">'django.contrib.gis.db.backends.postgis'</span><span class="p">,</span> <span class="s1">'NAME'</span><span class="p">:</span> <span class="s1">'geodjango'</span><span class="p">,</span> <span class="s1">'USER'</span><span class="p">:</span> <span class="s1">'geo'</span><span class="p">,</span> <span class="p">},</span> <span class="p">}</span> </pre></div> </div> <p>In addition, modify the <a class="reference internal" href="../../settings.html#std:setting-INSTALLED_APPS"><code class="xref std std-setting docutils literal"><span class="pre">INSTALLED_APPS</span></code></a> setting to include <a class="reference internal" href="../admin/index.html#module-django.contrib.admin" title="django.contrib.admin: Django's admin site."><code class="xref py py-mod docutils literal"><span class="pre">django.contrib.admin</span></code></a>, <a class="reference internal" href="index.html#module-django.contrib.gis" title="django.contrib.gis: Geographic Information System (GIS) extensions for Django"><code class="xref py py-mod docutils literal"><span class="pre">django.contrib.gis</span></code></a>, and <code class="docutils literal"><span class="pre">world</span></code> (your newly created application):</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">(</span> <span class="s1">'django.contrib.admin'</span><span class="p">,</span> <span class="s1">'django.contrib.auth'</span><span class="p">,</span> <span class="s1">'django.contrib.contenttypes'</span><span class="p">,</span> <span class="s1">'django.contrib.sessions'</span><span class="p">,</span> <span class="s1">'django.contrib.messages'</span><span class="p">,</span> <span class="s1">'django.contrib.staticfiles'</span><span class="p">,</span> <span class="s1">'django.contrib.gis'</span><span class="p">,</span> <span class="s1">'world'</span><span class="p">,</span> <span class="p">)</span> </pre></div> </div> </div> </div> <div class="section" id="s-geographic-data"> <span id="geographic-data"></span><h2>Geographic Data<a class="headerlink" href="#geographic-data" title="Permalink to this headline">¶</a></h2> <div class="section" id="s-worldborders"> <span id="s-id3"></span><span id="worldborders"></span><span id="id3"></span><h3>World Borders<a class="headerlink" href="#worldborders" title="Permalink to this headline">¶</a></h3> <p>The world borders data is available in this <a class="reference external" href="http://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip">zip file</a>. Create a <code class="docutils literal"><span class="pre">data</span></code> directory in the <code class="docutils literal"><span class="pre">world</span></code> application, download the world borders data, and unzip. On GNU/Linux platforms, use the following commands:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> mkdir world/data <span class="gp">$</span> <span class="nb">cd</span> world/data <span class="gp">$</span> wget http://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip <span class="gp">$</span> unzip TM_WORLD_BORDERS-0.3.zip <span class="gp">$</span> <span class="nb">cd</span> ../.. </pre></div> </div> <p>The world borders ZIP file contains a set of data files collectively known as an <a class="reference external" href="https://en.wikipedia.org/wiki/Shapefile">ESRI Shapefile</a>, one of the most popular geospatial data formats. When unzipped, the world borders dataset includes files with the following extensions:</p> <ul class="simple"> <li><code class="docutils literal"><span class="pre">.shp</span></code>: Holds the vector data for the world borders geometries.</li> <li><code class="docutils literal"><span class="pre">.shx</span></code>: Spatial index file for geometries stored in the <code class="docutils literal"><span class="pre">.shp</span></code>.</li> <li><code class="docutils literal"><span class="pre">.dbf</span></code>: Database file for holding non-geometric attribute data (e.g., integer and character fields).</li> <li><code class="docutils literal"><span class="pre">.prj</span></code>: Contains the spatial reference information for the geographic data stored in the shapefile.</li> </ul> </div> <div class="section" id="s-use-ogrinfo-to-examine-spatial-data"> <span id="use-ogrinfo-to-examine-spatial-data"></span><h3>Use <code class="docutils literal"><span class="pre">ogrinfo</span></code> to examine spatial data<a class="headerlink" href="#use-ogrinfo-to-examine-spatial-data" title="Permalink to this headline">¶</a></h3> <p>The GDAL <code class="docutils literal"><span class="pre">ogrinfo</span></code> utility allows examining the metadata of shapefiles or other vector data sources:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> ogrinfo world/data/TM_WORLD_BORDERS-0.3.shp <span class="go">INFO: Open of `world/data/TM_WORLD_BORDERS-0.3.shp'</span> <span class="go"> using driver `ESRI Shapefile' successful.</span> <span class="go">1: TM_WORLD_BORDERS-0.3 (Polygon)</span> </pre></div> </div> <p><code class="docutils literal"><span class="pre">ogrinfo</span></code> tells us that the shapefile has one layer, and that this layer contains polygon data. To find out more, we’ll specify the layer name and use the <code class="docutils literal"><span class="pre">-so</span></code> option to get only the important summary information:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> ogrinfo -so world/data/TM_WORLD_BORDERS-0.3.shp TM_WORLD_BORDERS-0.3 <span class="go">INFO: Open of `world/data/TM_WORLD_BORDERS-0.3.shp'</span> <span class="go"> using driver `ESRI Shapefile' successful.</span> <span class="go">Layer name: TM_WORLD_BORDERS-0.3</span> <span class="go">Geometry: Polygon</span> <span class="go">Feature Count: 246</span> <span class="go">Extent: (-180.000000, -90.000000) - (180.000000, 83.623596)</span> <span class="go">Layer SRS WKT:</span> <span class="go">GEOGCS["GCS_WGS_1984",</span> <span class="go"> DATUM["WGS_1984",</span> <span class="go"> SPHEROID["WGS_1984",6378137.0,298.257223563]],</span> <span class="go"> PRIMEM["Greenwich",0.0],</span> <span class="go"> UNIT["Degree",0.0174532925199433]]</span> <span class="go">FIPS: String (2.0)</span> <span class="go">ISO2: String (2.0)</span> <span class="go">ISO3: String (3.0)</span> <span class="go">UN: Integer (3.0)</span> <span class="go">NAME: String (50.0)</span> <span class="go">AREA: Integer (7.0)</span> <span class="go">POP2005: Integer (10.0)</span> <span class="go">REGION: Integer (3.0)</span> <span class="go">SUBREGION: Integer (3.0)</span> <span class="go">LON: Real (8.3)</span> <span class="go">LAT: Real (7.3)</span> </pre></div> </div> <p>This detailed summary information tells us the number of features in the layer (246), the geographic bounds of the data, the spatial reference system (“SRS WKT”), as well as type information for each attribute field. For example, <code class="docutils literal"><span class="pre">FIPS:</span> <span class="pre">String</span> <span class="pre">(2.0)</span></code> indicates that the <code class="docutils literal"><span class="pre">FIPS</span></code> character field has a maximum length of 2. Similarly, <code class="docutils literal"><span class="pre">LON:</span> <span class="pre">Real</span> <span class="pre">(8.3)</span></code> is a floating-point field that holds a maximum of 8 digits up to three decimal places.</p> </div> </div> <div class="section" id="s-geographic-models"> <span id="geographic-models"></span><h2>Geographic Models<a class="headerlink" href="#geographic-models" title="Permalink to this headline">¶</a></h2> <div class="section" id="s-defining-a-geographic-model"> <span id="defining-a-geographic-model"></span><h3>Defining a Geographic Model<a class="headerlink" href="#defining-a-geographic-model" title="Permalink to this headline">¶</a></h3> <p>Now that you’ve examined your dataset using <code class="docutils literal"><span class="pre">ogrinfo</span></code>, create a GeoDjango model to represent this data:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.gis.db</span> <span class="k">import</span> <span class="n">models</span> <span class="k">class</span> <span class="nc">WorldBorder</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span> <span class="c1"># Regular Django fields corresponding to the attributes in the</span> <span class="c1"># world borders shapefile.</span> <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span> <span class="n">area</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span> <span class="n">pop2005</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="s1">'Population 2005'</span><span class="p">)</span> <span class="n">fips</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="s1">'FIPS Code'</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="n">iso2</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="s1">'2 Digit ISO'</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="n">iso3</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="s1">'3 Digit ISO'</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="n">un</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="s1">'United Nations Code'</span><span class="p">)</span> <span class="n">region</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="s1">'Region Code'</span><span class="p">)</span> <span class="n">subregion</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">(</span><span class="s1">'Sub-Region Code'</span><span class="p">)</span> <span class="n">lon</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">FloatField</span><span class="p">()</span> <span class="n">lat</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">FloatField</span><span class="p">()</span> <span class="c1"># GeoDjango-specific: a geometry field (MultiPolygonField), and</span> <span class="c1"># overriding the default manager with a GeoManager instance.</span> <span class="n">mpoly</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">MultiPolygonField</span><span class="p">()</span> <span class="n">objects</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">GeoManager</span><span class="p">()</span> <span class="c1"># Returns the string representation of the model.</span> <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="c1"># __unicode__ on Python 2</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> </pre></div> </div> <p>Please note two important things:</p> <ol class="arabic simple"> <li>The <code class="docutils literal"><span class="pre">models</span></code> module is imported from <code class="docutils literal"><span class="pre">django.contrib.gis.db</span></code>.</li> <li>You must override the model’s default manager with <a class="reference internal" href="model-api.html#django.contrib.gis.db.models.GeoManager" title="django.contrib.gis.db.models.GeoManager"><code class="xref py py-class docutils literal"><span class="pre">GeoManager</span></code></a> to perform spatial queries.</li> </ol> <p>The default spatial reference system for geometry fields is WGS84 (meaning the <a class="reference external" href="https://en.wikipedia.org/wiki/SRID">SRID</a> is 4326) – in other words, the field coordinates are in longitude, latitude pairs in units of degrees. To use a different coordinate system, set the SRID of the geometry field with the <code class="docutils literal"><span class="pre">srid</span></code> argument. Use an integer representing the coordinate system’s EPSG code.</p> </div> <div class="section" id="s-run-migrate"> <span id="run-migrate"></span><h3>Run <code class="docutils literal"><span class="pre">migrate</span></code><a class="headerlink" href="#run-migrate" title="Permalink to this headline">¶</a></h3> <p>After defining your model, you need to sync it with the database. First, create a database migration:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py makemigrations <span class="go">Migrations for 'world':</span> <span class="go"> 0001_initial.py:</span> <span class="go"> - Create model WorldBorder</span> </pre></div> </div> <p>Let’s look at the SQL that will generate the table for the <code class="docutils literal"><span class="pre">WorldBorder</span></code> model:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py sqlmigrate world 0001 </pre></div> </div> <p>This command should produce the following output:</p> <div class="highlight-sql"><div class="highlight"><pre><span></span><span class="k">BEGIN</span><span class="p">;</span> <span class="k">CREATE</span> <span class="k">TABLE</span> <span class="ss">"world_worldborder"</span> <span class="p">(</span> <span class="ss">"id"</span> <span class="nb">serial</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span> <span class="ss">"name"</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">50</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"area"</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"pop2005"</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"fips"</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"iso2"</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"iso3"</span> <span class="nb">varchar</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"un"</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"region"</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"subregion"</span> <span class="nb">integer</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"lon"</span> <span class="n">double</span> <span class="k">precision</span> <span class="k">NOT</span> <span class="k">NULL</span><span class="p">,</span> <span class="ss">"lat"</span> <span class="n">double</span> <span class="k">precision</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="ss">"mpoly"</span> <span class="n">geometry</span><span class="p">(</span><span class="n">MULTIPOLYGON</span><span class="p">,</span><span class="mi">4326</span><span class="p">)</span> <span class="k">NOT</span> <span class="k">NULL</span> <span class="p">)</span> <span class="p">;</span> <span class="k">CREATE</span> <span class="k">INDEX</span> <span class="ss">"world_worldborder_mpoly_id"</span> <span class="k">ON</span> <span class="ss">"world_worldborder"</span> <span class="k">USING</span> <span class="n">GIST</span> <span class="p">(</span> <span class="ss">"mpoly"</span> <span class="p">);</span> <span class="k">COMMIT</span><span class="p">;</span> </pre></div> </div> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">With PostGIS < 2.0, the output is slightly different. The <code class="docutils literal"><span class="pre">mpoly</span></code> geometry column is added through a separate <code class="docutils literal"><span class="pre">SELECT</span> <span class="pre">AddGeometryColumn(...)</span></code> statement.</p> </div> <p>If this looks correct, run <a class="reference internal" href="../../django-admin.html#django-admin-migrate"><code class="xref std std-djadmin docutils literal"><span class="pre">migrate</span></code></a> to create this table in the database:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py migrate <span class="go">Operations to perform:</span> <span class="go"> Apply all migrations: admin, world, contenttypes, auth, sessions</span> <span class="go">Running migrations:</span> <span class="go"> ...</span> <span class="go"> Applying world.0001_initial... OK</span> </pre></div> </div> </div> </div> <div class="section" id="s-importing-spatial-data"> <span id="importing-spatial-data"></span><h2>Importing Spatial Data<a class="headerlink" href="#importing-spatial-data" title="Permalink to this headline">¶</a></h2> <p>This section will show you how to import the world borders shapefile into the database via GeoDjango models using the <a class="reference internal" href="layermapping.html"><span class="doc">LayerMapping data import utility</span></a>.</p> <p>There are many different ways to import data into a spatial database – besides the tools included within GeoDjango, you may also use the following:</p> <ul class="simple"> <li><a class="reference external" href="http://www.gdal.org/ogr2ogr.html">ogr2ogr</a>: A command-line utility included with GDAL that can import many vector data formats into PostGIS, MySQL, and Oracle databases.</li> <li><a class="reference external" href="http://postgis.net/docs/manual-1.5/ch04.html#shp2pgsql_usage">shp2pgsql</a>: This utility included with PostGIS imports ESRI shapefiles into PostGIS.</li> </ul> <div class="section" id="s-gdal-interface"> <span id="s-gdalinterface"></span><span id="gdal-interface"></span><span id="gdalinterface"></span><h3>GDAL Interface<a class="headerlink" href="#gdal-interface" title="Permalink to this headline">¶</a></h3> <p>Earlier, you used <code class="docutils literal"><span class="pre">ogrinfo</span></code> to examine the contents of the world borders shapefile. GeoDjango also includes a Pythonic interface to GDAL’s powerful OGR library that can work with all the vector data sources that OGR supports.</p> <p>First, invoke the Django shell:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py shell </pre></div> </div> <p>If you downloaded the <a class="reference internal" href="#worldborders"><span class="std std-ref">World Borders</span></a> data earlier in the tutorial, then you can determine its path using Python’s built-in <code class="docutils literal"><span class="pre">os</span></code> module:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">os</span> <span class="gp">>>> </span><span class="kn">import</span> <span class="nn">world</span> <span class="gp">>>> </span><span class="n">world_shp</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">world</span><span class="o">.</span><span class="n">__file__</span><span class="p">),</span> <span class="gp">... </span> <span class="s1">'data'</span><span class="p">,</span> <span class="s1">'TM_WORLD_BORDERS-0.3.shp'</span><span class="p">))</span> </pre></div> </div> <p>Now, open the world borders shapefile using GeoDjango’s <a class="reference internal" href="gdal.html#django.contrib.gis.gdal.DataSource" title="django.contrib.gis.gdal.DataSource"><code class="xref py py-class docutils literal"><span class="pre">DataSource</span></code></a> interface:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">django.contrib.gis.gdal</span> <span class="k">import</span> <span class="n">DataSource</span> <span class="gp">>>> </span><span class="n">ds</span> <span class="o">=</span> <span class="n">DataSource</span><span class="p">(</span><span class="n">world_shp</span><span class="p">)</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">ds</span><span class="p">)</span> <span class="go">/ ... /geodjango/world/data/TM_WORLD_BORDERS-0.3.shp (ESRI Shapefile)</span> </pre></div> </div> <p>Data source objects can have different layers of geospatial features; however, shapefiles are only allowed to have one layer:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">ds</span><span class="p">))</span> <span class="go">1</span> <span class="gp">>>> </span><span class="n">lyr</span> <span class="o">=</span> <span class="n">ds</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">lyr</span><span class="p">)</span> <span class="go">TM_WORLD_BORDERS-0.3</span> </pre></div> </div> <p>You can see the layer’s geometry type and how many features it contains:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">lyr</span><span class="o">.</span><span class="n">geom_type</span><span class="p">)</span> <span class="go">Polygon</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">lyr</span><span class="p">))</span> <span class="go">246</span> </pre></div> </div> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">Unfortunately, the shapefile data format does not allow for greater specificity with regards to geometry types. This shapefile, like many others, actually includes <code class="docutils literal"><span class="pre">MultiPolygon</span></code> geometries, not Polygons. It’s important to use a more general field type in models: a GeoDjango <code class="docutils literal"><span class="pre">MultiPolygonField</span></code> will accept a <code class="docutils literal"><span class="pre">Polygon</span></code> geometry, but a <code class="docutils literal"><span class="pre">PolygonField</span></code> will not accept a <code class="docutils literal"><span class="pre">MultiPolygon</span></code> type geometry. This is why the <code class="docutils literal"><span class="pre">WorldBorder</span></code> model defined above uses a <code class="docutils literal"><span class="pre">MultiPolygonField</span></code>.</p> </div> <p>The <a class="reference internal" href="gdal.html#django.contrib.gis.gdal.Layer" title="django.contrib.gis.gdal.Layer"><code class="xref py py-class docutils literal"><span class="pre">Layer</span></code></a> may also have a spatial reference system associated with it. If it does, the <code class="docutils literal"><span class="pre">srs</span></code> attribute will return a <a class="reference internal" href="gdal.html#django.contrib.gis.gdal.SpatialReference" title="django.contrib.gis.gdal.SpatialReference"><code class="xref py py-class docutils literal"><span class="pre">SpatialReference</span></code></a> object:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">srs</span> <span class="o">=</span> <span class="n">lyr</span><span class="o">.</span><span class="n">srs</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">srs</span><span class="p">)</span> <span class="go">GEOGCS["GCS_WGS_1984",</span> <span class="go"> DATUM["WGS_1984",</span> <span class="go"> SPHEROID["WGS_1984",6378137.0,298.257223563]],</span> <span class="go"> PRIMEM["Greenwich",0.0],</span> <span class="go"> UNIT["Degree",0.0174532925199433]]</span> <span class="gp">>>> </span><span class="n">srs</span><span class="o">.</span><span class="n">proj4</span> <span class="c1"># PROJ.4 representation</span> <span class="go">'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs '</span> </pre></div> </div> <p>This shapefile is in the popular WGS84 spatial reference system – in other words, the data uses longitude, latitude pairs in units of degrees.</p> <p>In addition, shapefiles also support attribute fields that may contain additional data. Here are the fields on the World Borders layer:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">lyr</span><span class="o">.</span><span class="n">fields</span><span class="p">)</span> <span class="go">['FIPS', 'ISO2', 'ISO3', 'UN', 'NAME', 'AREA', 'POP2005', 'REGION', 'SUBREGION', 'LON', 'LAT']</span> </pre></div> </div> <p>The following code will let you examine the OGR types (e.g. integer or string) associated with each of the fields:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="p">[</span><span class="n">fld</span><span class="o">.</span><span class="n">__name__</span> <span class="k">for</span> <span class="n">fld</span> <span class="ow">in</span> <span class="n">lyr</span><span class="o">.</span><span class="n">field_types</span><span class="p">]</span> <span class="go">['OFTString', 'OFTString', 'OFTString', 'OFTInteger', 'OFTString', 'OFTInteger', 'OFTInteger', 'OFTInteger', 'OFTInteger', 'OFTReal', 'OFTReal']</span> </pre></div> </div> <p>You can iterate over each feature in the layer and extract information from both the feature’s geometry (accessed via the <code class="docutils literal"><span class="pre">geom</span></code> attribute) as well as the feature’s attribute fields (whose <strong>values</strong> are accessed via <code class="docutils literal"><span class="pre">get()</span></code> method):</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="k">for</span> <span class="n">feat</span> <span class="ow">in</span> <span class="n">lyr</span><span class="p">:</span> <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="n">feat</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'NAME'</span><span class="p">),</span> <span class="n">feat</span><span class="o">.</span><span class="n">geom</span><span class="o">.</span><span class="n">num_points</span><span class="p">)</span> <span class="gp">...</span> <span class="go">Guernsey 18</span> <span class="go">Jersey 26</span> <span class="go">South Georgia South Sandwich Islands 338</span> <span class="go">Taiwan 363</span> </pre></div> </div> <p><a class="reference internal" href="gdal.html#django.contrib.gis.gdal.Layer" title="django.contrib.gis.gdal.Layer"><code class="xref py py-class docutils literal"><span class="pre">Layer</span></code></a> objects may be sliced:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">lyr</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span> <span class="go">[<django.contrib.gis.gdal.feature.Feature object at 0x2f47690>, <django.contrib.gis.gdal.feature.Feature object at 0x2f47650>]</span> </pre></div> </div> <p>And individual features may be retrieved by their feature ID:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">feat</span> <span class="o">=</span> <span class="n">lyr</span><span class="p">[</span><span class="mi">234</span><span class="p">]</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">feat</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'NAME'</span><span class="p">))</span> <span class="go">San Marino</span> </pre></div> </div> <p>Boundary geometries may be exported as WKT and GeoJSON:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">geom</span> <span class="o">=</span> <span class="n">feat</span><span class="o">.</span><span class="n">geom</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">geom</span><span class="o">.</span><span class="n">wkt</span><span class="p">)</span> <span class="go">POLYGON ((12.415798 43.957954,12.450554 ...</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">geom</span><span class="o">.</span><span class="n">json</span><span class="p">)</span> <span class="go">{ "type": "Polygon", "coordinates": [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...</span> </pre></div> </div> </div> <div class="section" id="s-layermapping"> <span id="layermapping"></span><h3><code class="docutils literal"><span class="pre">LayerMapping</span></code><a class="headerlink" href="#layermapping" title="Permalink to this headline">¶</a></h3> <p>To import the data, use a LayerMapping in a Python script. Create a file called <code class="docutils literal"><span class="pre">load.py</span></code> inside the <code class="docutils literal"><span class="pre">world</span></code> application, with the following code:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">os</span> <span class="kn">from</span> <span class="nn">django.contrib.gis.utils</span> <span class="k">import</span> <span class="n">LayerMapping</span> <span class="kn">from</span> <span class="nn">.models</span> <span class="k">import</span> <span class="n">WorldBorder</span> <span class="n">world_mapping</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">'fips'</span> <span class="p">:</span> <span class="s1">'FIPS'</span><span class="p">,</span> <span class="s1">'iso2'</span> <span class="p">:</span> <span class="s1">'ISO2'</span><span class="p">,</span> <span class="s1">'iso3'</span> <span class="p">:</span> <span class="s1">'ISO3'</span><span class="p">,</span> <span class="s1">'un'</span> <span class="p">:</span> <span class="s1">'UN'</span><span class="p">,</span> <span class="s1">'name'</span> <span class="p">:</span> <span class="s1">'NAME'</span><span class="p">,</span> <span class="s1">'area'</span> <span class="p">:</span> <span class="s1">'AREA'</span><span class="p">,</span> <span class="s1">'pop2005'</span> <span class="p">:</span> <span class="s1">'POP2005'</span><span class="p">,</span> <span class="s1">'region'</span> <span class="p">:</span> <span class="s1">'REGION'</span><span class="p">,</span> <span class="s1">'subregion'</span> <span class="p">:</span> <span class="s1">'SUBREGION'</span><span class="p">,</span> <span class="s1">'lon'</span> <span class="p">:</span> <span class="s1">'LON'</span><span class="p">,</span> <span class="s1">'lat'</span> <span class="p">:</span> <span class="s1">'LAT'</span><span class="p">,</span> <span class="s1">'mpoly'</span> <span class="p">:</span> <span class="s1">'MULTIPOLYGON'</span><span class="p">,</span> <span class="p">}</span> <span class="n">world_shp</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">),</span> <span class="s1">'data'</span><span class="p">,</span> <span class="s1">'TM_WORLD_BORDERS-0.3.shp'</span><span class="p">))</span> <span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="n">verbose</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span> <span class="n">lm</span> <span class="o">=</span> <span class="n">LayerMapping</span><span class="p">(</span><span class="n">WorldBorder</span><span class="p">,</span> <span class="n">world_shp</span><span class="p">,</span> <span class="n">world_mapping</span><span class="p">,</span> <span class="n">transform</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s1">'iso-8859-1'</span><span class="p">)</span> <span class="n">lm</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">strict</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="n">verbose</span><span class="p">)</span> </pre></div> </div> <p>A few notes about what’s going on:</p> <ul class="simple"> <li>Each key in the <code class="docutils literal"><span class="pre">world_mapping</span></code> dictionary corresponds to a field in the <code class="docutils literal"><span class="pre">WorldBorder</span></code> model. The value is the name of the shapefile field that data will be loaded from.</li> <li>The key <code class="docutils literal"><span class="pre">mpoly</span></code> for the geometry field is <code class="docutils literal"><span class="pre">MULTIPOLYGON</span></code>, the geometry type GeoDjango will import the field as. Even simple polygons in the shapefile will automatically be converted into collections prior to insertion into the database.</li> <li>The path to the shapefile is not absolute – in other words, if you move the <code class="docutils literal"><span class="pre">world</span></code> application (with <code class="docutils literal"><span class="pre">data</span></code> subdirectory) to a different location, the script will still work.</li> <li>The <code class="docutils literal"><span class="pre">transform</span></code> keyword is set to <code class="docutils literal"><span class="pre">False</span></code> because the data in the shapefile does not need to be converted – it’s already in WGS84 (SRID=4326).</li> <li>The <code class="docutils literal"><span class="pre">encoding</span></code> keyword is set to the character encoding of the string values in the shapefile. This ensures that string values are read and saved correctly from their original encoding system.</li> </ul> <p>Afterwards, invoke the Django shell from the <code class="docutils literal"><span class="pre">geodjango</span></code> project directory:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py shell </pre></div> </div> <p>Next, import the <code class="docutils literal"><span class="pre">load</span></code> module, call the <code class="docutils literal"><span class="pre">run</span></code> routine, and watch <code class="docutils literal"><span class="pre">LayerMapping</span></code> do the work:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">world</span> <span class="k">import</span> <span class="n">load</span> <span class="gp">>>> </span><span class="n">load</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> </pre></div> </div> </div> <div class="section" id="s-try-ogrinspect"> <span id="s-ogrinspect-intro"></span><span id="try-ogrinspect"></span><span id="ogrinspect-intro"></span><h3>Try <code class="docutils literal"><span class="pre">ogrinspect</span></code><a class="headerlink" href="#try-ogrinspect" title="Permalink to this headline">¶</a></h3> <p>Now that you’ve seen how to define geographic models and import data with the <a class="reference internal" href="layermapping.html"><span class="doc">LayerMapping data import utility</span></a>, it’s possible to further automate this process with use of the <a class="reference internal" href="commands.html#django-admin-ogrinspect"><code class="xref std std-djadmin docutils literal"><span class="pre">ogrinspect</span></code></a> management command. The <a class="reference internal" href="commands.html#django-admin-ogrinspect"><code class="xref std std-djadmin docutils literal"><span class="pre">ogrinspect</span></code></a> command introspects a GDAL-supported vector data source (e.g., a shapefile) and generates a model definition and <code class="docutils literal"><span class="pre">LayerMapping</span></code> dictionary automatically.</p> <p>The general usage of the command goes as follows:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py ogrinspect <span class="o">[</span>options<span class="o">]</span> <data_source> <model_name> <span class="o">[</span>options<span class="o">]</span> </pre></div> </div> <p><code class="docutils literal"><span class="pre">data_source</span></code> is the path to the GDAL-supported data source and <code class="docutils literal"><span class="pre">model_name</span></code> is the name to use for the model. Command-line options may be used to further define how the model is generated.</p> <p>For example, the following command nearly reproduces the <code class="docutils literal"><span class="pre">WorldBorder</span></code> model and mapping dictionary created above, automatically:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py ogrinspect world/data/TM_WORLD_BORDERS-0.3.shp WorldBorder <span class="se">\</span> <span class="go"> --srid=4326 --mapping --multi</span> </pre></div> </div> <p>A few notes about the command-line options given above:</p> <ul class="simple"> <li>The <code class="docutils literal"><span class="pre">--srid=4326</span></code> option sets the SRID for the geographic field.</li> <li>The <code class="docutils literal"><span class="pre">--mapping</span></code> option tells <code class="docutils literal"><span class="pre">ogrinspect</span></code> to also generate a mapping dictionary for use with <a class="reference internal" href="layermapping.html#django.contrib.gis.utils.LayerMapping" title="django.contrib.gis.utils.LayerMapping"><code class="xref py py-class docutils literal"><span class="pre">LayerMapping</span></code></a>.</li> <li>The <code class="docutils literal"><span class="pre">--multi</span></code> option is specified so that the geographic field is a <a class="reference internal" href="model-api.html#django.contrib.gis.db.models.MultiPolygonField" title="django.contrib.gis.db.models.MultiPolygonField"><code class="xref py py-class docutils literal"><span class="pre">MultiPolygonField</span></code></a> instead of just a <a class="reference internal" href="model-api.html#django.contrib.gis.db.models.PolygonField" title="django.contrib.gis.db.models.PolygonField"><code class="xref py py-class docutils literal"><span class="pre">PolygonField</span></code></a>.</li> </ul> <p>The command produces the following output, which may be copied directly into the <code class="docutils literal"><span class="pre">models.py</span></code> of a GeoDjango application:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="c1"># This is an auto-generated Django model module created by ogrinspect.</span> <span class="kn">from</span> <span class="nn">django.contrib.gis.db</span> <span class="k">import</span> <span class="n">models</span> <span class="k">class</span> <span class="nc">WorldBorder</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span> <span class="n">fips</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="n">iso2</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span> <span class="n">iso3</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span> <span class="n">un</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span> <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span> <span class="n">area</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span> <span class="n">pop2005</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span> <span class="n">region</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span> <span class="n">subregion</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">()</span> <span class="n">lon</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">FloatField</span><span class="p">()</span> <span class="n">lat</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">FloatField</span><span class="p">()</span> <span class="n">geom</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">MultiPolygonField</span><span class="p">(</span><span class="n">srid</span><span class="o">=</span><span class="mi">4326</span><span class="p">)</span> <span class="n">objects</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">GeoManager</span><span class="p">()</span> <span class="c1"># Auto-generated `LayerMapping` dictionary for WorldBorder model</span> <span class="n">worldborders_mapping</span> <span class="o">=</span> <span class="p">{</span> <span class="s1">'fips'</span> <span class="p">:</span> <span class="s1">'FIPS'</span><span class="p">,</span> <span class="s1">'iso2'</span> <span class="p">:</span> <span class="s1">'ISO2'</span><span class="p">,</span> <span class="s1">'iso3'</span> <span class="p">:</span> <span class="s1">'ISO3'</span><span class="p">,</span> <span class="s1">'un'</span> <span class="p">:</span> <span class="s1">'UN'</span><span class="p">,</span> <span class="s1">'name'</span> <span class="p">:</span> <span class="s1">'NAME'</span><span class="p">,</span> <span class="s1">'area'</span> <span class="p">:</span> <span class="s1">'AREA'</span><span class="p">,</span> <span class="s1">'pop2005'</span> <span class="p">:</span> <span class="s1">'POP2005'</span><span class="p">,</span> <span class="s1">'region'</span> <span class="p">:</span> <span class="s1">'REGION'</span><span class="p">,</span> <span class="s1">'subregion'</span> <span class="p">:</span> <span class="s1">'SUBREGION'</span><span class="p">,</span> <span class="s1">'lon'</span> <span class="p">:</span> <span class="s1">'LON'</span><span class="p">,</span> <span class="s1">'lat'</span> <span class="p">:</span> <span class="s1">'LAT'</span><span class="p">,</span> <span class="s1">'geom'</span> <span class="p">:</span> <span class="s1">'MULTIPOLYGON'</span><span class="p">,</span> <span class="p">}</span> </pre></div> </div> </div> </div> <div class="section" id="s-spatial-queries"> <span id="spatial-queries"></span><h2>Spatial Queries<a class="headerlink" href="#spatial-queries" title="Permalink to this headline">¶</a></h2> <div class="section" id="s-spatial-lookups"> <span id="spatial-lookups"></span><h3>Spatial Lookups<a class="headerlink" href="#spatial-lookups" title="Permalink to this headline">¶</a></h3> <p>GeoDjango adds spatial lookups to the Django ORM. For example, you can find the country in the <code class="docutils literal"><span class="pre">WorldBorder</span></code> table that contains a particular point. First, fire up the management shell:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py shell </pre></div> </div> <p>Now, define a point of interest <a class="footnote-reference" href="#id12" id="id7">[3]</a>:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">pnt_wkt</span> <span class="o">=</span> <span class="s1">'POINT(-95.3385 29.7245)'</span> </pre></div> </div> <p>The <code class="docutils literal"><span class="pre">pnt_wkt</span></code> string represents the point at -95.3385 degrees longitude, 29.7245 degrees latitude. The geometry is in a format known as Well Known Text (WKT), a standard issued by the Open Geospatial Consortium (OGC). <a class="footnote-reference" href="#id13" id="id8">[4]</a> Import the <code class="docutils literal"><span class="pre">WorldBorder</span></code> model, and perform a <code class="docutils literal"><span class="pre">contains</span></code> lookup using the <code class="docutils literal"><span class="pre">pnt_wkt</span></code> as the parameter:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">world.models</span> <span class="k">import</span> <span class="n">WorldBorder</span> <span class="gp">>>> </span><span class="n">qs</span> <span class="o">=</span> <span class="n">WorldBorder</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">mpoly__contains</span><span class="o">=</span><span class="n">pnt_wkt</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">qs</span> <span class="go">[<WorldBorder: United States>]</span> </pre></div> </div> <p>Here, you retrieved a <code class="docutils literal"><span class="pre">GeoQuerySet</span></code> with only one model: the border of the United States (exactly what you would expect).</p> <p>Similarly, you may also use a <a class="reference internal" href="geos.html"><span class="doc">GEOS geometry object</span></a>. Here, you can combine the <code class="docutils literal"><span class="pre">intersects</span></code> spatial lookup with the <code class="docutils literal"><span class="pre">get</span></code> method to retrieve only the <code class="docutils literal"><span class="pre">WorldBorder</span></code> instance for San Marino instead of a queryset:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">django.contrib.gis.geos</span> <span class="k">import</span> <span class="n">Point</span> <span class="gp">>>> </span><span class="n">pnt</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="mf">12.4604</span><span class="p">,</span> <span class="mf">43.9420</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">sm</span> <span class="o">=</span> <span class="n">WorldBorder</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">mpoly__intersects</span><span class="o">=</span><span class="n">pnt</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">sm</span> <span class="go"><WorldBorder: San Marino></span> </pre></div> </div> <p>The <code class="docutils literal"><span class="pre">contains</span></code> and <code class="docutils literal"><span class="pre">intersects</span></code> lookups are just a subset of the available queries – the <a class="reference internal" href="db-api.html"><span class="doc">GeoDjango Database API</span></a> documentation has more.</p> </div> <div class="section" id="s-automatic-spatial-transformations"> <span id="automatic-spatial-transformations"></span><h3>Automatic Spatial Transformations<a class="headerlink" href="#automatic-spatial-transformations" title="Permalink to this headline">¶</a></h3> <p>When doing spatial queries, GeoDjango automatically transforms geometries if they’re in a different coordinate system. In the following example, coordinates will be expressed in <a class="reference external" href="http://spatialreference.org/ref/epsg/32140/">EPSG SRID 32140</a>, a coordinate system specific to south Texas <strong>only</strong> and in units of <strong>meters</strong>, not degrees:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">django.contrib.gis.geos</span> <span class="k">import</span> <span class="n">Point</span><span class="p">,</span> <span class="n">GEOSGeometry</span> <span class="gp">>>> </span><span class="n">pnt</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="mf">954158.1</span><span class="p">,</span> <span class="mf">4215137.1</span><span class="p">,</span> <span class="n">srid</span><span class="o">=</span><span class="mi">32140</span><span class="p">)</span> </pre></div> </div> <p>Note that <code class="docutils literal"><span class="pre">pnt</span></code> may also be constructed with EWKT, an “extended” form of WKT that includes the SRID:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">pnt</span> <span class="o">=</span> <span class="n">GEOSGeometry</span><span class="p">(</span><span class="s1">'SRID=32140;POINT(954158.1 4215137.1)'</span><span class="p">)</span> </pre></div> </div> <p>GeoDjango’s ORM will automatically wrap geometry values in transformation SQL, allowing the developer to work at a higher level of abstraction:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">qs</span> <span class="o">=</span> <span class="n">WorldBorder</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">mpoly__intersects</span><span class="o">=</span><span class="n">pnt</span><span class="p">)</span> <span class="gp">>>> </span><span class="nb">print</span><span class="p">(</span><span class="n">qs</span><span class="o">.</span><span class="n">query</span><span class="p">)</span> <span class="c1"># Generating the SQL</span> <span class="go">SELECT "world_worldborder"."id", "world_worldborder"."name", "world_worldborder"."area",</span> <span class="go">"world_worldborder"."pop2005", "world_worldborder"."fips", "world_worldborder"."iso2",</span> <span class="go">"world_worldborder"."iso3", "world_worldborder"."un", "world_worldborder"."region",</span> <span class="go">"world_worldborder"."subregion", "world_worldborder"."lon", "world_worldborder"."lat",</span> <span class="go">"world_worldborder"."mpoly" FROM "world_worldborder"</span> <span class="go">WHERE ST_Intersects("world_worldborder"."mpoly", ST_Transform(%s, 4326))</span> <span class="gp">>>> </span><span class="n">qs</span> <span class="c1"># printing evaluates the queryset</span> <span class="go">[<WorldBorder: United States>]</span> </pre></div> </div> <div class="admonition-raw-queries admonition"> <p class="first admonition-title">Raw queries</p> <p>When using <a class="reference internal" href="../../../topics/db/sql.html"><span class="doc">raw queries</span></a>, you should generally wrap your geometry fields with the <code class="docutils literal"><span class="pre">asText()</span></code> SQL function (or <code class="docutils literal"><span class="pre">ST_AsText</span></code> for PostGIS) so that the field value will be recognized by GEOS:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">City</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">raw</span><span class="p">(</span><span class="s1">'SELECT id, name, asText(point) from myapp_city'</span><span class="p">)</span> </pre></div> </div> <p class="last">This is not absolutely required by PostGIS, but generally you should only use raw queries when you know exactly what you are doing.</p> </div> </div> <div class="section" id="s-lazy-geometries"> <span id="lazy-geometries"></span><h3>Lazy Geometries<a class="headerlink" href="#lazy-geometries" title="Permalink to this headline">¶</a></h3> <p>GeoDjango loads geometries in a standardized textual representation. When the geometry field is first accessed, GeoDjango creates a <cite>GEOS geometry object <ref-geos></cite>, exposing powerful functionality, such as serialization properties for popular geospatial formats:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">sm</span> <span class="o">=</span> <span class="n">WorldBorder</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'San Marino'</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">sm</span><span class="o">.</span><span class="n">mpoly</span> <span class="go"><MultiPolygon object at 0x24c6798></span> <span class="gp">>>> </span><span class="n">sm</span><span class="o">.</span><span class="n">mpoly</span><span class="o">.</span><span class="n">wkt</span> <span class="c1"># WKT</span> <span class="go">MULTIPOLYGON (((12.4157980000000006 43.9579540000000009, 12.4505540000000003 43.9797209999999978, ...</span> <span class="gp">>>> </span><span class="n">sm</span><span class="o">.</span><span class="n">mpoly</span><span class="o">.</span><span class="n">wkb</span> <span class="c1"># WKB (as Python binary buffer)</span> <span class="go"><read-only buffer for 0x1fe2c70, size -1, offset 0 at 0x2564c40></span> <span class="gp">>>> </span><span class="n">sm</span><span class="o">.</span><span class="n">mpoly</span><span class="o">.</span><span class="n">geojson</span> <span class="c1"># GeoJSON (requires GDAL)</span> <span class="go">'{ "type": "MultiPolygon", "coordinates": [ [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...</span> </pre></div> </div> <p>This includes access to all of the advanced geometric operations provided by the GEOS library:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">pnt</span> <span class="o">=</span> <span class="n">Point</span><span class="p">(</span><span class="mf">12.4604</span><span class="p">,</span> <span class="mf">43.9420</span><span class="p">)</span> <span class="gp">>>> </span><span class="n">sm</span><span class="o">.</span><span class="n">mpoly</span><span class="o">.</span><span class="n">contains</span><span class="p">(</span><span class="n">pnt</span><span class="p">)</span> <span class="go">True</span> <span class="gp">>>> </span><span class="n">pnt</span><span class="o">.</span><span class="n">contains</span><span class="p">(</span><span class="n">sm</span><span class="o">.</span><span class="n">mpoly</span><span class="p">)</span> <span class="go">False</span> </pre></div> </div> </div> <div class="section" id="s-geoqueryset-methods"> <span id="geoqueryset-methods"></span><h3><code class="docutils literal"><span class="pre">GeoQuerySet</span></code> Methods<a class="headerlink" href="#geoqueryset-methods" title="Permalink to this headline">¶</a></h3> </div> </div> <div class="section" id="s-putting-your-data-on-the-map"> <span id="putting-your-data-on-the-map"></span><h2>Putting your data on the map<a class="headerlink" href="#putting-your-data-on-the-map" title="Permalink to this headline">¶</a></h2> <div class="section" id="s-geographic-admin"> <span id="geographic-admin"></span><h3>Geographic Admin<a class="headerlink" href="#geographic-admin" title="Permalink to this headline">¶</a></h3> <p>GeoDjango extends <a class="reference internal" href="../admin/index.html"><span class="doc">Django’s admin application</span></a> with support for editing geometry fields.</p> <div class="section" id="s-basics"> <span id="basics"></span><h4>Basics<a class="headerlink" href="#basics" title="Permalink to this headline">¶</a></h4> <p>GeoDjango also supplements the Django admin by allowing users to create and modify geometries on a JavaScript slippy map (powered by <a class="reference external" href="http://openlayers.org/">OpenLayers</a>).</p> <p>Let’s dive right in. Create a file called <code class="docutils literal"><span class="pre">admin.py</span></code> inside the <code class="docutils literal"><span class="pre">world</span></code> application with the following code:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.contrib.gis</span> <span class="k">import</span> <span class="n">admin</span> <span class="kn">from</span> <span class="nn">.models</span> <span class="k">import</span> <span class="n">WorldBorder</span> <span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">WorldBorder</span><span class="p">,</span> <span class="n">admin</span><span class="o">.</span><span class="n">GeoModelAdmin</span><span class="p">)</span> </pre></div> </div> <p>Next, edit your <code class="docutils literal"><span class="pre">urls.py</span></code> in the <code class="docutils literal"><span class="pre">geodjango</span></code> application folder as follows:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">django.conf.urls</span> <span class="k">import</span> <span class="n">url</span><span class="p">,</span> <span class="n">include</span> <span class="kn">from</span> <span class="nn">django.contrib.gis</span> <span class="k">import</span> <span class="n">admin</span> <span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span> <span class="n">url</span><span class="p">(</span><span class="s1">r'^admin/'</span><span class="p">,</span> <span class="n">include</span><span class="p">(</span><span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">urls</span><span class="p">)),</span> <span class="p">]</span> </pre></div> </div> <p>Create an admin user:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py createsuperuser </pre></div> </div> <p>Next, start up the Django development server:</p> <div class="highlight-console"><div class="highlight"><pre><span></span><span class="gp">$</span> python manage.py runserver </pre></div> </div> <p>Finally, browse to <code class="docutils literal"><span class="pre">http://localhost:8000/admin/</span></code>, and log in with the user you just created. Browse to any of the <code class="docutils literal"><span class="pre">WorldBorder</span></code> entries – the borders may be edited by clicking on a polygon and dragging the vertexes to the desired position.</p> </div> <div class="section" id="s-osmgeoadmin"> <span id="s-osmgeoadmin-intro"></span><span id="osmgeoadmin"></span><span id="osmgeoadmin-intro"></span><h4><code class="docutils literal"><span class="pre">OSMGeoAdmin</span></code><a class="headerlink" href="#osmgeoadmin" title="Permalink to this headline">¶</a></h4> <p>With the <a class="reference internal" href="admin.html#django.contrib.gis.admin.OSMGeoAdmin" title="django.contrib.gis.admin.OSMGeoAdmin"><code class="xref py py-class docutils literal"><span class="pre">OSMGeoAdmin</span></code></a>, GeoDjango uses a <a class="reference external" href="http://www.openstreetmap.org/">Open Street Map</a> layer in the admin. This provides more context (including street and thoroughfare details) than available with the <a class="reference internal" href="admin.html#django.contrib.gis.admin.GeoModelAdmin" title="django.contrib.gis.admin.GeoModelAdmin"><code class="xref py py-class docutils literal"><span class="pre">GeoModelAdmin</span></code></a> (which uses the <a class="reference external" href="http://earth-info.nga.mil/publications/vmap0.html">Vector Map Level 0</a> WMS dataset hosted at <a class="reference external" href="http://www.osgeo.org">OSGeo</a>).</p> <p>First, there are some important requirements:</p> <ul class="simple"> <li><a class="reference internal" href="admin.html#django.contrib.gis.admin.OSMGeoAdmin" title="django.contrib.gis.admin.OSMGeoAdmin"><code class="xref py py-class docutils literal"><span class="pre">OSMGeoAdmin</span></code></a> requires that <a class="reference internal" href="gdal.html"><span class="doc">GDAL</span></a> is installed.</li> <li>The PROJ.4 datum shifting files must be installed (see the <a class="reference internal" href="install/geolibs.html#proj4"><span class="std std-ref">PROJ.4 installation instructions</span></a> for more details).</li> </ul> <p>If you meet this requirement, then just substitute the <code class="docutils literal"><span class="pre">OSMGeoAdmin</span></code> option class in your <code class="docutils literal"><span class="pre">admin.py</span></code> file:</p> <div class="highlight-default"><div class="highlight"><pre><span></span><span class="n">admin</span><span class="o">.</span><span class="n">site</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">WorldBorder</span><span class="p">,</span> <span class="n">admin</span><span class="o">.</span><span class="n">OSMGeoAdmin</span><span class="p">)</span> </pre></div> </div> <p class="rubric">Footnotes</p> <table class="docutils footnote" frame="void" id="id10" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>Special thanks to Bjørn Sandvik of <a class="reference external" href="http://thematicmapping.org">thematicmapping.org</a> for providing and maintaining this dataset.</td></tr> </tbody> </table> <table class="docutils footnote" frame="void" id="id11" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id2">[2]</a></td><td>GeoDjango basic apps was written by Dane Springmeyer, Josh Livni, and Christopher Schmidt.</td></tr> </tbody> </table> <table class="docutils footnote" frame="void" id="id12" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id7">[3]</a></td><td>This point is the <a class="reference external" href="http://www.law.uh.edu/">University of Houston Law Center</a>.</td></tr> </tbody> </table> <table class="docutils footnote" frame="void" id="id13" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id8">[4]</a></td><td>Open Geospatial Consortium, Inc., <a class="reference external" href="http://www.opengeospatial.org/standards/sfs">OpenGIS Simple Feature Specification For SQL</a>.</td></tr> </tbody> </table> </div> </div> </div> </div> </div> </div> </div> <div class="yui-b" id="sidebar"> <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> <div class="sphinxsidebarwrapper"> <h3><a href="../../../contents.html">Table Of Contents</a></h3> <ul> <li><a class="reference internal" href="#">GeoDjango Tutorial</a><ul> <li><a class="reference internal" href="#introduction">Introduction</a></li> <li><a class="reference internal" href="#setting-up">Setting Up</a><ul> <li><a class="reference internal" href="#create-a-spatial-database">Create a Spatial Database</a></li> <li><a class="reference internal" href="#create-a-new-project">Create a New Project</a></li> <li><a class="reference internal" href="#configure-settings-py">Configure <code class="docutils literal"><span class="pre">settings.py</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#geographic-data">Geographic Data</a><ul> <li><a class="reference internal" href="#worldborders">World Borders</a></li> <li><a class="reference internal" href="#use-ogrinfo-to-examine-spatial-data">Use <code class="docutils literal"><span class="pre">ogrinfo</span></code> to examine spatial data</a></li> </ul> </li> <li><a class="reference internal" href="#geographic-models">Geographic Models</a><ul> <li><a class="reference internal" href="#defining-a-geographic-model">Defining a Geographic Model</a></li> <li><a class="reference internal" href="#run-migrate">Run <code class="docutils literal"><span class="pre">migrate</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#importing-spatial-data">Importing Spatial Data</a><ul> <li><a class="reference internal" href="#gdal-interface">GDAL Interface</a></li> <li><a class="reference internal" href="#layermapping"><code class="docutils literal"><span class="pre">LayerMapping</span></code></a></li> <li><a class="reference internal" href="#try-ogrinspect">Try <code class="docutils literal"><span class="pre">ogrinspect</span></code></a></li> </ul> </li> <li><a class="reference internal" href="#spatial-queries">Spatial Queries</a><ul> <li><a class="reference internal" href="#spatial-lookups">Spatial Lookups</a></li> <li><a class="reference internal" href="#automatic-spatial-transformations">Automatic Spatial Transformations</a></li> <li><a class="reference internal" href="#lazy-geometries">Lazy Geometries</a></li> <li><a class="reference internal" href="#geoqueryset-methods"><code class="docutils literal"><span class="pre">GeoQuerySet</span></code> Methods</a></li> </ul> </li> <li><a class="reference internal" href="#putting-your-data-on-the-map">Putting your data on the map</a><ul> <li><a class="reference internal" href="#geographic-admin">Geographic Admin</a><ul> <li><a class="reference internal" href="#basics">Basics</a></li> <li><a class="reference internal" href="#osmgeoadmin"><code class="docutils literal"><span class="pre">OSMGeoAdmin</span></code></a></li> </ul> </li> </ul> </li> </ul> </li> </ul> <h3>Browse</h3> <ul> <li>Prev: <a href="index.html">GeoDjango</a></li> <li>Next: <a href="install/index.html">GeoDjango Installation</a></li> </ul> <h3>You are here:</h3> <ul> <li> <a href="../../../index.html">Django 1.8.19 documentation</a> <ul><li><a href="../../index.html">API Reference</a> <ul><li><a href="../index.html"><code class="docutils literal"><span class="pre">contrib</span></code> packages</a> <ul><li><a href="index.html">GeoDjango</a> <ul><li>GeoDjango Tutorial</li></ul> </li></ul></li></ul></li></ul> </li> </ul> <div role="note" aria-label="source link"> <h3>This Page</h3> <ul class="this-page-menu"> <li><a href="../../../_sources/ref/contrib/gis/tutorial.txt" rel="nofollow">Show Source</a></li> </ul> </div> <div id="searchbox" style="display: none" role="search"> <h3>Quick search</h3> <form class="search" action="../../../search.html" method="get"> <div><input type="text" name="q" /></div> <div><input type="submit" value="Go" /></div> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> </div> <script type="text/javascript">$('#searchbox').show(0);</script> </div> </div> <h3>Last update:</h3> <p class="topless">Feb 12, 2019</p> </div> </div> <div id="ft"> <div class="nav"> « <a href="index.html" title="GeoDjango">previous</a> | <a href="../../index.html" title="API Reference" accesskey="U">up</a> | <a href="install/index.html" title="GeoDjango Installation">next</a> »</div> </div> </div> <div class="clearer"></div> </div> </body> </html>