One View Per Layer: Four Sharp Edges I Found in My Own Code
There is a layer in my database called 1 . Somebody created it, presumably by accident, and it sat there for months looking harmless. It was the only layer in the system that never served a single tile, and nobody noticed, because it was empty anyway. That layer turned out to be a symptom of a SQL injection vulnerability. This post is about the design that produced it — which I still think is a good design — and the four things I got wrong inside it. The setup A web GIS with about 2.7 million features: 1.8 million points, 697,000 lines, 172,000 polygons. Users create layers through the UI, upload data into them, edit geometry, and expect to see it on a map. The features do not live in a table per layer. They live in three tables — one for points, one for lines, one for polygons — with a layer_id foreign key and a JSON column for attributes: project_pointfeature 1,820,288 rows project_linefeature 697,009 rows project_polygonfeature 171,830 rows That's a deliberate trade. A table per layer means DDL every time a user clicks "new layer", a migration story that never ends, and a schema that drifts. Three generic tables mean one schema, one set of indexes, and layers that are just rows in a metadata table. The cost lands on the tile server. The pattern Martin serves vector tiles from PostGIS. Point it at a database and it discovers spatial tables and views and publishes each as an MVT endpoint. It can be told to publish views but not tables: postgres : auto_publish : from_schemas : [ public ] publish_tables : false reload_interval : 5s So: give every layer its own view. A Django post_save signal on the Layer model creates it: CREATE OR REPLACE VIEW t19_saobracajni_znakovi AS SELECT f . id , f . feature_attrs , f . geom , f . layer_id , l . name AS layer_name , lg . name AS layer_group_name , p . title AS project_title FROM project_pointfeature f JOIN project_layer l ON f . layer_id = l . id JOIN project_layergroup lg ON l . layer_group_id = lg . id JOIN project_project p