Skip to main content

Django app for importing and managing Who's On First geographic data

Project description

django-whosonfirst

A Django app for importing and managing Who's On First geographic data.

Who's On First (WOF) is an open, global gazetteer that provides stable place IDs, explicit hierarchies, and polygon geometries for geographic entities—from continents and countries down to cities and neighbourhoods.

Features

  • Download WOF SQLite data bundles (global or per-country)
  • Import places with full hierarchy (continent → country → region → locality → neighbourhood)
  • Store geometries in PostGIS
  • Map to GeoNames and Wikidata via concordances
  • Extensible plugin system for custom processing

Requirements

  • Python 3.10+
  • Django 4.2+
  • PostgreSQL with PostGIS extension
  • django.contrib.gis configured

Installation

pip install django-whosonfirst

Add to your INSTALLED_APPS:

INSTALLED_APPS = [
    # ...
    'django.contrib.gis',
    'whosonfirst',
]

Run migrations:

python manage.py migrate whosonfirst

Quick Start

1. Download WOF Data

Download data for specific countries:

# Download US and Canada
python manage.py wof_download --countries=US,CA

# Download all countries (large!)
python manage.py wof_download

2. Import Data

# Import downloaded data
python manage.py wof_import

# Import specific countries
python manage.py wof_import --countries=US,CA

# Import specific placetypes
python manage.py wof_import --placetypes=country,region,locality

# Import without geometry (faster, smaller database)
python manage.py wof_import --no-geometry

3. Query Places

from whosonfirst.models import Place

# Get all countries
countries = Place.objects.filter(placetype='country')

# Get cities in the US
us_cities = Place.objects.filter(
    placetype='locality',
    country_code='US'
)

# Get a place by WOF ID
sf = Place.objects.get(wof_id=85922583)  # San Francisco

# Get ancestors
sf.get_ancestors()  # Returns California, US, North America

# Get descendants
ca = Place.objects.get(wof_id=85688637)  # California
ca.get_descendants(placetype='locality')  # All cities in CA

# Query by GeoNames ID
place = Place.objects.get(geonames_id=5391959)

# Query by Wikidata ID
place = Place.objects.get(wikidata_id='Q62')

Management Commands

wof_download

Download WOF SQLite data bundles.

# Download specific countries
python manage.py wof_download --countries=US,CA,MX

# Force re-download
python manage.py wof_download --countries=US --force

# List cached bundles
python manage.py wof_download --list

# Clear cache
python manage.py wof_download --clear

wof_import

Import WOF data into Django models.

# Import all downloaded data
python manage.py wof_import

# Import specific countries
python manage.py wof_import --countries=US

# Import specific placetypes
python manage.py wof_import --placetypes=country,region,locality,neighbourhood

# Flush existing data before import
python manage.py wof_import --flush=all

# Dry run (parse without saving)
python manage.py wof_import --dry-run

# Skip geometry import
python manage.py wof_import --no-geometry

# Skip alternative names
python manage.py wof_import --no-names

wof_update

Update data (download fresh and import changes).

python manage.py wof_update --countries=US

# Check for changes without importing
python manage.py wof_update --check-only

wof_build_index

Build derived indices and resolve relationships.

# Run all index operations
python manage.py wof_build_index --all

# Resolve parent relationships only
python manage.py wof_build_index --resolve-parents

Configuration

Configure via Django settings:

# Data directory for downloads (default: app's data/ directory)
WOF_DATA_DIR = '/path/to/wof/data'

# Placetypes to import by default
WOF_PLACETYPES = [
    'continent',
    'country',
    'region',
    'locality',
    'neighbourhood',
]

# Country codes to import (empty = all)
WOF_COUNTRY_CODES = ['US', 'CA', 'MX']

# Whether to import geometry (default: True)
WOF_IMPORT_GEOMETRY = True

# Skip deprecated places (default: True)
WOF_SKIP_DEPRECATED = True

# Skip places marked as not current (default: False)
WOF_SKIP_NOT_CURRENT = False

# Languages to import for alternative names (ISO 639-3 codes)
# Default: ['eng'] (English only)
# Use empty list [] to import all languages
WOF_LANGUAGES = ['eng']

# HTTP download timeout in seconds (default: 300)
WOF_DOWNLOAD_TIMEOUT = 300

# Maximum download size in bytes (default: 10GB)
WOF_MAX_DOWNLOAD_SIZE = 10 * 1024 * 1024 * 1024

# Batch size for bulk operations (default: 1000)
WOF_BATCH_SIZE = 1000

# Plugin classes for custom processing
WOF_PLUGINS = ['myapp.plugins.MyWOFPlugin']

Placetypes

WOF uses a hierarchy of placetypes:

Placetype Description Example
continent Continents North America
country Countries United States
dependency Dependencies Puerto Rico
region First-level admin (states/provinces) California
county Counties Los Angeles County
localadmin Local administrative areas City of Los Angeles
locality Cities/towns San Francisco
borough Boroughs Manhattan
neighbourhood Neighbourhoods Mission District
venue Points of interest Golden Gate Bridge

Default import includes: continent, country, dependency, region, county, localadmin, locality

Models

Place

The main model storing all WOF places.

class Place(models.Model):
    # Identity
    wof_id = BigIntegerField(primary_key=True)
    placetype = CharField(max_length=50)
    name = CharField(max_length=255)
    slug = SlugField(max_length=255)
    country_code = CharField(max_length=2)

    # Hierarchy
    parent = ForeignKey('self', null=True)
    parent_wof_id = BigIntegerField(null=True)
    belongsto = JSONField(default=list)  # Ancestor WOF IDs
    hierarchy = JSONField(default=list)

    # Geometry (PostGIS)
    geom = MultiPolygonField(null=True, srid=4326)
    centroid = PointField(null=True, srid=4326)
    latitude = FloatField(null=True)
    longitude = FloatField(null=True)
    bbox = JSONField(null=True)

    # Concordances
    concordances = JSONField(default=dict)
    geonames_id = BigIntegerField(null=True)
    wikidata_id = CharField(max_length=20)

    # Metadata
    lastmodified = BigIntegerField(null=True)
    is_current = BooleanField(default=True)
    is_deprecated = BooleanField(default=False)

PlaceName

Alternative names in different languages.

class PlaceName(models.Model):
    place = ForeignKey(Place)
    name = CharField(max_length=255)
    language = CharField(max_length=10)  # ISO 639-3
    name_type = CharField(max_length=20)  # preferred, variant, etc.
    is_preferred = BooleanField(default=False)

Plugins

Create custom plugins to hook into the import process:

# myapp/plugins.py
from whosonfirst.exceptions import HookException

class MyWOFPlugin:
    def place_pre(self, command, item):
        """Called before parsing each place.

        Args:
            command: Management command instance
            item: Raw data dict from parser

        Raises:
            HookException: Skip this item
        """
        # Skip places without geometry
        if not item.get('geometry'):
            raise HookException('No geometry')

        # Modify item in place
        item['name'] = item['name'].title()

    def place_post(self, command, obj, item):
        """Called after saving each place.

        Args:
            command: Management command instance
            obj: Saved Place model instance
            item: Raw data dict
        """
        if obj.placetype == 'locality':
            # Custom processing for cities
            pass

Register in settings:

WOF_PLUGINS = ['myapp.plugins.MyWOFPlugin']

Concordances

WOF includes mappings to external datasets. Access via the concordances JSONField or dedicated fields:

place = Place.objects.get(name='San Francisco', placetype='locality')

# GeoNames ID
place.geonames_id  # 5391959

# Wikidata QID
place.wikidata_id  # 'Q62'

# All concordances
place.concordances
# {
#     'geonames_id': 5391959,
#     'wikidata_id': 'Q62',
#     'fips_code': '06075',
#     'iso_code': 'US-CA',
#     ...
# }

Disclaimer

This project is not affiliated with, endorsed by, or associated with Who's On First, Mapzen, or Geocode Earth. It is an independent, third-party Django integration that consumes publicly available Who's On First data.

License

MIT License

WOF Data License

Who's On First data is licensed under various open licenses. See WOF Licenses for details.

When using WOF data, please provide appropriate attribution.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_whosonfirst-0.1.0.tar.gz (35.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_whosonfirst-0.1.0-py3-none-any.whl (45.9 kB view details)

Uploaded Python 3

File details

Details for the file django_whosonfirst-0.1.0.tar.gz.

File metadata

  • Download URL: django_whosonfirst-0.1.0.tar.gz
  • Upload date:
  • Size: 35.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_whosonfirst-0.1.0.tar.gz
Algorithm Hash digest
SHA256 869daa5cb8d61230eb1a227281d250230d350945b1a797df8fc14e0bf2ad239c
MD5 67fd345ebe6543cd338c44fa652cfb5f
BLAKE2b-256 5091b8dc76272009df975c4896ce485d6d939509e4c146a78325aceea31151e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_whosonfirst-0.1.0.tar.gz:

Publisher: publish.yml on arthanson/django-whosonfirst

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_whosonfirst-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_whosonfirst-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e03cd5f9462acf87886974429d5d30132331013f426f477e53543f6ff535e9c5
MD5 24e1810b3326ba80f8e458edd54cacd5
BLAKE2b-256 ac886a9ca81d958deabb3b3c46ec8dafe16c82e3fd5ca558725a0aa7e44d1098

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_whosonfirst-0.1.0-py3-none-any.whl:

Publisher: publish.yml on arthanson/django-whosonfirst

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page