The problem
Oahu's Realtor Neighborhood boundaries - the informal areas real estate listings get grouped into, like "Waipahu Estates" or "Mililani Area" - haven't had an up-to-date map to visualize where they actually sit.
That gap was a good excuse to learn GeoDjango properly, working with real geospatial data, so I combined the two: build a tool that lets me review the existing boundaries and correct them over time, while learning PostGIS and spatial querying along the way.
The approach
The app is built in Django with PostGIS, using GeoDjango's spatial fields and a Neighborhood model with a MultiPolygonField for the boundary geometry.
- The source shapefile represents each neighborhood as one or more separate polygon pieces - 958 individual shapes covering 370 distinct neighborhoods in total, since many span disconnected areas. I wrote an import command that groups these by neighborhood and region, unions each group's pieces into a single clean geometry, and reprojects everything from the source data's coordinate system into WGS84.
- Regions are modeled as their own table with a foreign key from Neighborhood, rather than a free-text field - small deliberate choice, but it means a typo can't silently fragment a region, and each region carries its own color used consistently across the map and its legend.
- The public map is built with Leaflet and MapTiler tiles, styled with Tailwind, and lets you toggle between viewing all regions at once (color-coded by region) or drilling into a single region to see individual neighborhoods.
- Boundary editing happens through a customized Django admin, using GeoDjango's built-in map widget so I can nudge, reshape, or redraw a neighborhood's geometry directly against a real basemap.
- Performance mattered more than expected once real geometry was involved - the initial unsimplified GeoJSON payload came in at nearly 100 MB. Simplifying geometry server-side with PostGIS and adding gzip compression brought that down to about 1.4 MB transferred, without a visible loss in boundary accuracy at normal zoom levels.
What I'd do differently
I'd nail down the production settings split (dev vs. prod) and environment variable handling earlier - I patched those in as issues came up post-deploy rather than deciding on a clean approach up front, which cost more debugging time than it should have. I'd also plan the Region-as-a-model change before the first import rather than after, since retrofitting a foreign key onto already-imported data is more work than designing for it from the start.
Result
The map is live and reviewable, with all 370 neighborhoods imported, color-coded by region, and editable directly through the admin. Boundary review itself is ongoing - the point of the tool is to make that an easy, continuous process rather than a one-time fix - but the infrastructure to actually do that work is done.