Skip to content

Commit

Permalink
Merge #155
Browse files Browse the repository at this point in the history
155: Military symbols for narrations. r=MiklerGM a=whirish

Closes #94. Adds two models - `Symbol` and `SymbolFeature`. Symbol is intended to be a single FeatureCollection storing individual SymbolFeatures, and has a o2m relationship with SymbolFeature as a result. SymbolFeatures stores geometry and an hstore field `styling`, which will store styling information as GeoJSON `properties`. 
Symbol features have a GeoJSON-compatible endpoint, and can be requested as  `/api/symbol-features/?symbol=<symbol id>/`, which returns a FeatureCollection containing all SymbolFeatures for a specified Symbol ID. @MiklerGM please tell me if this arrangement works for you. We can also add query params for filtering based on narration IDs, etc.
Old Chronist narratives should be available for import after this is merged.

Co-authored-by: whirish <lpoflynn@protonmail.ch>
  • Loading branch information
bors[bot] and quorth0n authored Nov 5, 2019
2 parents 420807b + dec5626 commit 48676b2
Show file tree
Hide file tree
Showing 9 changed files with 185 additions and 1 deletion.
4 changes: 4 additions & 0 deletions project/api/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
City,
Profile,
NarrativeVote,
Symbol,
SymbolFeature,
)

# Register your models here.
Expand All @@ -43,3 +45,5 @@
admin.site.register(City)
admin.site.register(Profile)
admin.site.register(NarrativeVote)
admin.site.register(Symbol)
admin.site.register(SymbolFeature)
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 2.2.4 on 2019-08-08 19:58

from django.conf import settings
import django.contrib.gis.db.models.fields
from django.contrib.postgres.operations import HStoreExtension
import django.contrib.postgres.fields.hstore
from django.db import migrations, models
import django.db.models.deletion
import simple_history.models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('api', '0015_merge_20190627_1103'),
]

operations = [
HStoreExtension(),
migrations.CreateModel(
name='Symbol',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.TextField(max_length=50)),
],
),
migrations.CreateModel(
name='SymbolFeature',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('geom', django.contrib.gis.db.models.fields.GeometryField(srid=4326)),
('styling', django.contrib.postgres.fields.hstore.HStoreField()),
('symbol', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='features', to='api.Symbol')),
],
),
migrations.CreateModel(
name='HistoricalSymbol',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('name', models.TextField(max_length=50)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical symbol',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]
18 changes: 18 additions & 0 deletions project/api/migrations/0017_symbol_narration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-08-08 23:07

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('api', '0016_historicalsymbol_symbol_symbolfeature'),
]

operations = [
migrations.AddField(
model_name='symbol',
name='narration',
field=models.ManyToManyField(related_name='symbols', to='api.Narration'),
),
]
18 changes: 18 additions & 0 deletions project/api/migrations/0018_auto_20190809_0035.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-08-09 00:35

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('api', '0017_symbol_narration'),
]

operations = [
migrations.RenameField(
model_name='symbol',
old_name='narration',
new_name='narrations',
),
]
24 changes: 23 additions & 1 deletion project/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
from django.contrib.gis.db import models
from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.fields import ArrayField, HStoreField
from django.db.models.signals import post_save
from django.dispatch import receiver
from ordered_model.models import OrderedModel
Expand Down Expand Up @@ -385,3 +385,25 @@ class Narration(OrderedModel):
location = models.PointField(blank=True, null=True)

order_with_respect_to = "narrative"


class Symbol(models.Model):
"""
Stores a FeatureCollection in representation of something
"""

name = models.TextField(max_length=50)
narrations = models.ManyToManyField(Narration, related_name="symbols")
history = HistoricalRecords()


class SymbolFeature(models.Model):
"""
Stores geometry to be used in a collection in a Symbol
"""

geom = models.GeometryField()
styling = HStoreField()
symbol = models.ForeignKey(
Symbol, related_name="features", on_delete=models.CASCADE
)
35 changes: 35 additions & 0 deletions project/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@
PrimaryKeyRelatedField,
SerializerMethodField,
)
from rest_framework_gis.serializers import GeoFeatureModelSerializer

from .models import (
TerritorialEntity,
PoliticalRelation,
Symbol,
SymbolFeature,
CachedData,
City,
SpacetimeVolume,
Expand Down Expand Up @@ -119,6 +122,38 @@ class Meta:
read_only_fields = ("rank",)


class SymbolFeatureSerializer(GeoFeatureModelSerializer):
"""
Symbolizes SymbolFeatures as valid GeoJSON
"""

class Meta:
model = SymbolFeature
geo_field = "geom"
fields = "__all__"

def get_properties(self, instance, fields):
return instance.styling

def unformat_geojson(self, feature):
attrs = {
self.Meta.geo_field: feature["geometry"],
"styling": feature["properties"],
}

return attrs


class SymbolSerializer(ModelSerializer):
"""
Serializes the Symbol model
"""

class Meta:
model = Symbol
fields = ("id", "name", "narrations", "features")


class CitySerializer(ModelSerializer):
"""
Serializes the City model
Expand Down
2 changes: 2 additions & 0 deletions project/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
ROUTER.register(r"narrations", views.NarrationViewSet)
ROUTER.register(r"narrative-votes", views.NarrativeVoteViewSet)
ROUTER.register(r"profiles", views.ProfileViewSet)
ROUTER.register(r"symbols", views.SymbolViewSet)
ROUTER.register(r"symbol-features", views.SymbolFeatureViewSet)

urlpatterns = [
path(
Expand Down
29 changes: 29 additions & 0 deletions project/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
Narration,
NarrativeVote,
Profile,
Symbol,
SymbolFeature,
)
from .serializers import (
TerritorialEntitySerializer,
Expand All @@ -47,6 +49,8 @@
NarrationSerializer,
NarrativeVoteSerializer,
ProfileSerializer,
SymbolSerializer,
SymbolFeatureSerializer,
)
from .permissions import IsUserOrReadOnly

Expand Down Expand Up @@ -184,6 +188,31 @@ def get_queryset(self):
return queryset


class SymbolFeatureViewSet(viewsets.ModelViewSet):
"""
ViewSet for SymbolFeatures, filterable by Symbol id
"""

queryset = SymbolFeature.objects.all()
serializer_class = SymbolFeatureSerializer

def get_queryset(self):
queryset = self.queryset
symbol = self.request.query_params.get("symbol", None)
if symbol is not None:
queryset = queryset.filter(symbol=symbol)
return queryset


class SymbolViewSet(viewsets.ModelViewSet):
"""
ViewSet for Symbols
"""

queryset = Symbol.objects.all()
serializer_class = SymbolSerializer


class ProfileViewSet(viewsets.ModelViewSet):
"""
ViewSet for Profile
Expand Down
1 change: 1 addition & 0 deletions project/chron/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.gis",
"django.contrib.postgres",
"django_extensions",
"api.apps.ApiConfig",
"colorfield",
Expand Down

0 comments on commit 48676b2

Please sign in to comment.