Skip to content

Commit

Permalink
Add style defaults
Browse files Browse the repository at this point in the history
  • Loading branch information
meomancer committed May 30, 2024
1 parent 82ed05a commit 2f75eec
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 14 deletions.
1 change: 1 addition & 0 deletions deployment/docker/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Django==4.2.7

# Web APIs for Django
djangorestframework==3.14.0
drf-nested-routers==0.93.5

# Geographic add-ons for Django Rest Framework
djangorestframework-gis==1.0
Expand Down
11 changes: 10 additions & 1 deletion django_project/context_layer_management/admin/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.contrib import admin

from context_layer_management.forms.layer import LayerForm, LayerUploadForm
from context_layer_management.forms.style import LayerStyleForm
from context_layer_management.models.layer import Layer, LayerField, LayerStyle
from context_layer_management.models.layer_upload import LayerUpload
from context_layer_management.tasks import import_data
Expand Down Expand Up @@ -63,8 +64,9 @@ class LayerUploadAdmin(admin.ModelAdmin):
"""Layer admin."""

list_display = (
'layer', 'created_by', 'created_at', 'folder', 'status', 'note'
'created_at', 'created_by', 'layer', 'status', 'progress', 'note'
)
list_filter = ['layer', 'status']
actions = [start_upload_data]
form = LayerUploadForm

Expand All @@ -78,10 +80,17 @@ def get_form(self, request, *args, **kwargs):
class LayerStyleAdmin(admin.ModelAdmin):
"""Layer Style admin."""

form = LayerStyleForm
list_display = (
'name', 'created_by', 'created_at'
)

def get_form(self, request, *args, **kwargs):
"""Return form."""
form = super(LayerStyleAdmin, self).get_form(request, *args, **kwargs)
form.user = request.user
return form


admin.site.register(Layer, LayerAdmin)
admin.site.register(LayerStyle, LayerStyleAdmin)
Expand Down
16 changes: 11 additions & 5 deletions django_project/context_layer_management/api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,12 @@
from rest_framework.viewsets import mixins, GenericViewSet


class BaseApi(
class BaseReadApi(
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
GenericViewSet
):
"""Base API for Resource."""

"""Base Read API View."""
form_class = None
lookup_field = 'id'

Expand Down Expand Up @@ -83,6 +80,15 @@ def retrieve(self, request, *args, **kwargs):
serializer = self.get_serializer(instance)
return Response(serializer.data)


class BaseApi(
BaseReadApi,
mixins.RetrieveModelMixin,
mixins.DestroyModelMixin,
GenericViewSet
):
"""Base API for Resource."""

def create(self, request, *args, **kwargs):
"""Update an object."""
data = request.data.copy()
Expand Down
54 changes: 52 additions & 2 deletions django_project/context_layer_management/api/layer.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# coding=utf-8
"""Context Layer Management."""

from context_layer_management.api.base import BaseApi
from django.http import Http404
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response

from context_layer_management.api.base import BaseApi, BaseReadApi
from context_layer_management.forms.layer import LayerForm
from context_layer_management.models.layer import Layer
from context_layer_management.forms.style import LayerStyleForm
from context_layer_management.models.layer import Layer, LayerStyle
from context_layer_management.serializer.layer import LayerSerializer
from context_layer_management.serializer.style import StyleOfLayerSerializer


class LayerViewSet(BaseApi):
Expand All @@ -22,3 +28,47 @@ def get_serializer_context(self):
'view': self,
'user': self.request.user
}


class StyleOfLayerViewSet(BaseReadApi):
"""API layer style."""

form_class = LayerStyleForm
serializer_class = StyleOfLayerSerializer

def _get_layer(self) -> Layer: # noqa: D102
layer_id = self.kwargs.get('layer_id')
return get_object_or_404(
Layer.objects.filter(pk=layer_id)
)

def get_serializer_context(self):
"""Extra context provided to the serializer class."""
return {
'request': self.request,
'format': self.format_kwarg,
'view': self,
'user': self.request.user,
'layer': self._get_layer()
}

def get_serializer(self, *args, **kwargs):
"""Return the serializer instance."""
serializer_class = self.get_serializer_class()
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)

def get_queryset(self):
"""Return queryset of API."""
layer = self._get_layer()
ids = layer.styles.values_list('id', flat=True)
return LayerStyle.objects.filter(id__in=ids)

def list(self, request, *args, **kwargs):
"""Return just default style."""
layer = self._get_layer()
if layer.default_style:
serializer = self.get_serializer(layer.default_style)
return Response(serializer.data)
else:
raise Http404
20 changes: 20 additions & 0 deletions django_project/context_layer_management/forms/style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# coding=utf-8
"""Context Layer Management."""

from django import forms

from context_layer_management.models import LayerStyle


class LayerStyleForm(forms.ModelForm):
"""Layer style form."""

def save(self, commit=True):
"""Save the data."""
if not self.instance.created_by_id:
self.instance.created_by_id = self.user.pk
return super(LayerStyleForm, self).save(commit=commit)

class Meta: # noqa: D106
model = LayerStyle
exclude = ()
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.7 on 2024-05-30 03:12
# Generated by Django 4.2.7 on 2024-05-30 06:26

import context_layer_management.models.layer_upload
from django.conf import settings
Expand Down Expand Up @@ -58,7 +58,7 @@ class Migration(migrations.Migration):
('description', models.TextField(blank=True, null=True)),
('created_at', models.DateTimeField(default=django.utils.timezone.now, editable=False)),
('style', models.JSONField(help_text='Contains mapbox style information.')),
('created_by', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('created_by', models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
Expand Down
10 changes: 9 additions & 1 deletion django_project/context_layer_management/models/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import uuid

from django.conf import settings
from django.db import models, connection
from django.contrib.auth import get_user_model
from django.db import connection, models
from django.db.models.signals import post_delete
from django.dispatch import receiver
from django.urls import reverse
Expand All @@ -23,6 +24,8 @@
settings.MEDIA_URL, FOLDER_FILES
)

User = get_user_model()


class LayerType(object):
"""A quick couple of variable and Layer type."""
Expand All @@ -34,6 +37,11 @@ class LayerType(object):
class LayerStyle(AbstractTerm, AbstractResource):
"""Model contains layer information."""

created_by = models.ForeignKey(
User, on_delete=models.CASCADE,
editable=False, null=True, blank=True
)

style = models.JSONField(
help_text=(
'Contains mapbox style information.'
Expand Down
24 changes: 22 additions & 2 deletions django_project/context_layer_management/models/layer_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
from django.dispatch import receiver

from context_layer_management.models.general import AbstractResource
from context_layer_management.models.layer import Layer, LayerField
from context_layer_management.models.layer import Layer, LayerField, LayerStyle
from context_layer_management.models.style_defaults import (
LINE, POINT, POLYGON
)
from context_layer_management.tasks import import_data
from context_layer_management.utils.connection import fields
from context_layer_management.utils.geopandas import shapefile_to_postgis
Expand Down Expand Up @@ -156,6 +159,23 @@ def import_data(self):

layer.is_ready = True
layer.metadata = metadata

# Update default style
geometry_type = metadata['GEOMETRY TYPE'].lower()
if not layer.default_style_id:
default_style = POINT
if 'line' in geometry_type:
default_style = LINE
elif 'polygon' in geometry_type:
default_style = POLYGON
style, _ = LayerStyle.objects.get_or_create(
name=f'Default {geometry_type}',
defaults={
'style': default_style
}
)
layer.default_style = style
layer.styles.add(style)
layer.save()
except Exception as e:
# Save fields to layer
Expand All @@ -170,7 +190,7 @@ def import_data(self):
note='',
progress=100
)
self.delete_folder()
self.delete_folder()


@receiver(post_delete, sender=LayerUpload)
Expand Down
47 changes: 47 additions & 0 deletions django_project/context_layer_management/models/style_defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
POINT = {
"layers": [
{
"id": "<uuid>",
"type": "circle",
"paint": {
"circle-color": "#ff7800",
"circle-radius": 4,
"circle-opacity": 1
},
"filter": ["==", "$type", "Point"],
"source": "<uuid>",
"source-layer": "default"
}
]
}
LINE = {
"layers": [
{
"id": "<uuid>",
"type": "line",
"source": "<uuid>",
"source-layer": "default",
"filter": ["==", "$type", "LineString"],
"paint": {
"line-color": "#ff7800",
"line-width": 1
},
}
]
}

POLYGON = {
"layers": [
{
"id": "<uuid>",
"type": "fill",
"source": "<uuid>",
"source-layer": "default",
"filter": ["==", "$type", "Polygon"],
"paint": {
"fill-color": "#ff7800",
"fill-opacity": 0.8
},
}
]
}
46 changes: 46 additions & 0 deletions django_project/context_layer_management/serializer/style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# coding=utf-8
"""Context Layer Management."""

import json

from rest_framework import serializers

from context_layer_management.models.layer import LayerStyle


class StyleOfLayerSerializer(serializers.ModelSerializer):
"""Serializer for layer."""

def get_style(self, obj: LayerStyle):
"""Return style."""
style = obj.style
layer = self.context.get('layer', None)
request = self.context.get('request', None)
if layer:
# Append uuid to style
if 'sources' not in style:
style['sources'] = {}
style['sources'][str(layer.unique_id)] = {
"tiles": [
request.build_absolute_uri('/')[:-1] + layer.tile_url
],
"type": "vector"
}
style = json.dumps(style).replace(
'<uuid>', str(layer.unique_id)
)
style = json.loads(style)

# Append version
if 'version' not in style:
style['version'] = 8
return style

def to_representation(self, instance):
data = super(StyleOfLayerSerializer, self).to_representation(instance)
data.update(self.get_style(obj=instance))
return data

class Meta: # noqa: D106
model = LayerStyle
fields = []
13 changes: 12 additions & 1 deletion django_project/context_layer_management/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@

from django.urls import include, path
from rest_framework.routers import DefaultRouter
from rest_framework_nested.routers import NestedSimpleRouter

from context_layer_management.api.layer import LayerViewSet
from context_layer_management.api.layer import (
LayerViewSet, StyleOfLayerViewSet
)
from context_layer_management.api.vector_tile import (VectorTileLayer)

router = DefaultRouter()
router.register(
r'layer', LayerViewSet, basename='context-layer-management-view-set'
)
layer_router = NestedSimpleRouter(
router, r'layer', lookup='layer'
)
layer_router.register(
'style', StyleOfLayerViewSet,
basename='context-layer-management-style-view-set'
)

urlpatterns = [
path(
Expand All @@ -19,4 +29,5 @@
name='context-layer-management-tile-api'
),
path('api/', include(router.urls)),
path('api/', include(layer_router.urls)),
]

0 comments on commit 2f75eec

Please sign in to comment.