Skip to content

Commit ddeedda

Browse files
committed
Add VectorDataset and VectorItem models & views
1 parent a939496 commit ddeedda

File tree

20 files changed

+380
-28
lines changed

20 files changed

+380
-28
lines changed

Dockerfile

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
1-
FROM python:3.13-slim as base
2-
FROM base as builder
1+
FROM ubuntu:24.04
2+
ARG DEBIAN_FRONTEND=noninteractive
33

4-
# Allows docker to cache installed dependencies between builds
5-
RUN apt-get update && apt-get -y install libpq-dev gcc
4+
RUN apt-get update -qq -y \
5+
&& apt-get install -y binutils libproj-dev python3-gdal libgeos-dev libyaml-dev python3-pip \
6+
&& apt-get clean \
67
COPY ./requirements.txt requirements.txt
7-
RUN pip3 install --no-cache-dir --target=packages -r requirements.txt
8+
RUN pip install --no-cache-dir --target=packages -r requirements.txt
89

9-
FROM base as runtime
10-
COPY --from=builder packages /usr/lib/python3.12/site-packages
11-
ENV PYTHONPATH=/usr/lib/python3.12/site-packages
12-
13-
# Security Context
14-
RUN useradd -m nonroot
15-
USER nonroot
16-
17-
COPY . code
18-
WORKDIR code
10+
COPY . /app
11+
RUN useradd django
12+
RUN chown -R django:django /app
13+
WORKDIR /app
1914

2015
EXPOSE 8000
2116
# Run the production server

docker-compose.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,23 @@ services:
3636
- ./:/code
3737
ports:
3838
- "8001:8001"
39+
titiler:
40+
image: ghcr.io/developmentseed/titiler:latest
41+
container_name: titiler
42+
platform: linux/amd64
43+
environment:
44+
CPL_TMPDIR: /tmp
45+
GDAL_CACHEMAX: 75%
46+
VSI_CACHE: TRUE
47+
VSI_CACHE_SIZE: 1073741824
48+
GDAL_DISABLE_READDIR_ON_OPEN: EMPTY_DIR
49+
GDAL_HTTP_MERGE_CONSECUTIVE_RANGES: YES
50+
GDAL_HTTP_MULTIPLEX: YES
51+
GDAL_HTTP_VERSION: 2
52+
PYTHONWARNINGS: ignore
53+
WEB_CONCURRENCY: 4
54+
ports:
55+
- "8002:8000"
56+
volumes:
57+
- ./data:/data # Optional: mount local directory with your raster files
58+
restart: unless-stopped

requirements.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Core
2-
Django==5.1.7
2+
Django==5.2.5
33
django-configurations==2.5.1
44
gunicorn==23.0.0
55
setuptools==78.1.1
@@ -13,8 +13,11 @@ django-model-utils==5.0.0
1313
django_unique_upload==0.2.1
1414

1515
# Rest apis
16-
djangorestframework==3.15.2
16+
djangorestframework==3.16.1
17+
djangorestframework-gis==1.2.0
1718
django-filter==24.3
19+
drf_spectacular==0.28.0
20+
django-cors-headers==4.7.0
1821

1922
# Developer Tools
2023
ipdb==0.13.13
@@ -24,6 +27,6 @@ flake8==7.1.1
2427

2528
# Testing
2629
mock==5.1.0
27-
factory-boy==3.3.1
30+
factory-boy==3.3.3
2831
pytest-django==4.9.0
2932
coverage==7.6.9

vbos/config/common.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Common(Configuration):
1010

1111
INSTALLED_APPS = (
1212
"django.contrib.admin",
13+
"django.contrib.gis",
1314
"django.contrib.auth",
1415
"django.contrib.contenttypes",
1516
"django.contrib.sessions",
@@ -18,15 +19,20 @@ class Common(Configuration):
1819
# Third party apps
1920
"rest_framework", # utilities for rest apis
2021
"rest_framework.authtoken", # token authentication
22+
"rest_framework_gis",
23+
"drf_spectacular", # api-docs
2124
"django_filters", # for filtering rest endpoints
25+
"corsheaders",
2226
# Your apps
2327
"vbos.users",
28+
"vbos.datasets",
2429
)
2530

2631
# https://docs.djangoproject.com/en/2.0/topics/http/middleware/
2732
MIDDLEWARE = (
2833
"django.middleware.security.SecurityMiddleware",
2934
"django.contrib.sessions.middleware.SessionMiddleware",
35+
"corsheaders.middleware.CorsMiddleware",
3036
"django.middleware.common.CommonMiddleware",
3137
"django.middleware.csrf.CsrfViewMiddleware",
3238
"django.contrib.auth.middleware.AuthenticationMiddleware",
@@ -47,7 +53,9 @@ class Common(Configuration):
4753
# Postgres
4854
DATABASES = {
4955
"default": dj_database_url.config(
50-
default="postgis://postgres:@postgres:5432/vbos",
56+
default=os.getenv(
57+
"DJANGO_DB_URL", "postgis://postgres:@postgres:5432/vbos"
58+
),
5159
conn_max_age=int(os.getenv("POSTGRES_CONN_MAX_AGE", 600)),
5260
)
5361
}
@@ -187,4 +195,12 @@ class Common(Configuration):
187195
"rest_framework.authentication.SessionAuthentication",
188196
"rest_framework.authentication.TokenAuthentication",
189197
),
198+
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
199+
}
200+
201+
SPECTACULAR_SETTINGS = {
202+
"TITLE": "VBOS-API",
203+
"DESCRIPTION": "VBoS Management Information System API",
204+
"VERSION": "1.0.0",
205+
"SERVE_INCLUDE_SCHEMA": False,
190206
}

vbos/config/local.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ class Local(Common):
1414
EMAIL_HOST = "localhost"
1515
EMAIL_PORT = 1025
1616
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
17+
18+
# CORS
19+
CORS_ALLOW_ALL_ORIGINS = True

vbos/datasets/__init__.py

Whitespace-only changes.

vbos/datasets/admin.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from django.contrib.gis import admin
2+
from .models import VectorDataset, VectorItem
3+
4+
5+
@admin.register(VectorDataset)
6+
class VectorDatasetAdmin(admin.ModelAdmin):
7+
list_display = ["id", "name", "created", "updated"]
8+
9+
10+
@admin.register(VectorItem)
11+
class VectorItemAdmin(admin.GISModelAdmin):
12+
list_display = ["id", "metadata"]
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Generated by Django 5.2.5 on 2025-08-29 16:45
2+
3+
import django.contrib.gis.db.models.fields
4+
import django.db.models.deletion
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
initial = True
11+
12+
dependencies = []
13+
14+
operations = [
15+
migrations.CreateModel(
16+
name="VectorDataset",
17+
fields=[
18+
(
19+
"id",
20+
models.AutoField(
21+
auto_created=True,
22+
primary_key=True,
23+
serialize=False,
24+
verbose_name="ID",
25+
),
26+
),
27+
("name", models.CharField(max_length=155)),
28+
("created", models.DateTimeField(auto_now_add=True)),
29+
("updated", models.DateTimeField(auto_now=True)),
30+
],
31+
options={
32+
"ordering": ["id"],
33+
},
34+
),
35+
migrations.CreateModel(
36+
name="VectorItem",
37+
fields=[
38+
(
39+
"id",
40+
models.AutoField(
41+
auto_created=True,
42+
primary_key=True,
43+
serialize=False,
44+
verbose_name="ID",
45+
),
46+
),
47+
(
48+
"geometry",
49+
django.contrib.gis.db.models.fields.GeometryField(srid=4326),
50+
),
51+
("metadata", models.JSONField(blank=True, default=dict, null=True)),
52+
(
53+
"dataset",
54+
models.ForeignKey(
55+
on_delete=django.db.models.deletion.CASCADE,
56+
to="datasets.vectordataset",
57+
),
58+
),
59+
],
60+
options={
61+
"ordering": ["id"],
62+
},
63+
),
64+
]

vbos/datasets/migrations/__init__.py

Whitespace-only changes.

vbos/datasets/models.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from django.contrib.gis.db import models
2+
3+
4+
class VectorDataset(models.Model):
5+
name = models.CharField(max_length=155)
6+
created = models.DateTimeField(auto_now_add=True)
7+
updated = models.DateTimeField(auto_now=True)
8+
9+
def __str__(self):
10+
return self.name
11+
12+
class Meta:
13+
ordering = ["id"]
14+
15+
16+
class VectorItem(models.Model):
17+
dataset = models.ForeignKey(VectorDataset, on_delete=models.CASCADE)
18+
geometry = models.GeometryField()
19+
metadata = models.JSONField(default=dict, blank=True, null=True)
20+
21+
def __str__(self):
22+
return self.id
23+
24+
class Meta:
25+
ordering = ["id"]

0 commit comments

Comments
 (0)