#138 WIP Improvements
* adds geom back writing to form field in case of invalid geometry, so the invalid geometry will be shown again * updates tests * fixes bug where race condition of celery workers could lead to duplicates in parcels (needs migration)
This commit is contained in:
@@ -293,26 +293,33 @@ class SimpleGeomForm(BaseForm):
|
||||
geom = self.instance.geometry.geom
|
||||
geom.transform(ct=DEFAULT_SRID_RLP)
|
||||
self.empty = geom.empty
|
||||
if self.empty:
|
||||
raise AttributeError
|
||||
geom = geom.geojson
|
||||
except AttributeError:
|
||||
# If no geometry exists for this form, we simply set the value to None and zoom to the maximum level
|
||||
geom = ""
|
||||
self.empty = True
|
||||
self.fields["geom"].widget.attrs["default_zoom"] = 1
|
||||
|
||||
self.initialize_form_field("geom", geom)
|
||||
|
||||
def is_valid(self):
|
||||
super_valid = super().is_valid()
|
||||
super().is_valid()
|
||||
is_valid = True
|
||||
|
||||
# Get geojson from form
|
||||
geom = self.data["geom"]
|
||||
geom = json.loads(geom)
|
||||
|
||||
# Write submitted data back into form field to make sure invalid geometry
|
||||
# will be rendered again on failed submit
|
||||
self.initialize_form_field("geom", self.data["geom"])
|
||||
|
||||
# Read geojson into gdal geometry
|
||||
# HINT: This can be simplified if the geojson format holds data in epsg:4326 (GDAL provides direct creation for
|
||||
# this case)
|
||||
features = []
|
||||
features_json = geom["features"]
|
||||
features_json = geom.get("features", [])
|
||||
for feature in features_json:
|
||||
g = gdal.OGRGeometry(json.dumps(feature["geometry"]), srs=DEFAULT_SRID_RLP)
|
||||
if g.geom_type not in ["Polygon", "MultiPolygon"]:
|
||||
@@ -327,9 +334,12 @@ class SimpleGeomForm(BaseForm):
|
||||
form_geom.transform(coord_trans=DEFAULT_SRID)
|
||||
if form_geom.geom_type != "MultiPolygon":
|
||||
form_geom = MultiPolygon(MultiPolygon.from_ewkt(form_geom.ewkt))
|
||||
self.cleaned_data = {
|
||||
"geom": form_geom.wkt
|
||||
}
|
||||
|
||||
# Write unioned Multipolygon into cleaned data
|
||||
if self.cleaned_data is None:
|
||||
self.cleaned_data = {}
|
||||
self.cleaned_data["geom"] = form_geom.wkt
|
||||
|
||||
return is_valid
|
||||
|
||||
def save(self, action: UserActionLogEntry):
|
||||
|
||||
17
konova/migrations/0010_auto_20220420_1034.py
Normal file
17
konova/migrations/0010_auto_20220420_1034.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 3.1.3 on 2022-04-20 08:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('konova', '0009_auto_20220411_1004'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddConstraint(
|
||||
model_name='parcel',
|
||||
constraint=models.UniqueConstraint(fields=('district', 'municipal', 'parcel_group', 'flr', 'flrstck_nnr', 'flrstck_zhlr'), name='Unique parcel constraint'),
|
||||
),
|
||||
]
|
||||
25
konova/migrations/0011_auto_20220420_1101.py
Normal file
25
konova/migrations/0011_auto_20220420_1101.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 3.1.3 on 2022-04-20 09:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('konova', '0010_auto_20220420_1034'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddConstraint(
|
||||
model_name='district',
|
||||
constraint=models.UniqueConstraint(fields=('key', 'name'), name='Unique district constraint'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='municipal',
|
||||
constraint=models.UniqueConstraint(fields=('key', 'name', 'district'), name='Unique municipal constraint'),
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='parcelgroup',
|
||||
constraint=models.UniqueConstraint(fields=('key', 'name', 'municipal'), name='Unique parcel group constraint'),
|
||||
),
|
||||
]
|
||||
@@ -6,7 +6,7 @@ Created on: 15.11.21
|
||||
|
||||
"""
|
||||
from django.contrib.gis.db.models import MultiPolygonField
|
||||
from django.db import models
|
||||
from django.db import models, transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from konova.models import BaseResource, UuidModel
|
||||
@@ -96,6 +96,7 @@ class Geometry(BaseResource):
|
||||
objs += set_objs
|
||||
return objs
|
||||
|
||||
@transaction.atomic
|
||||
def update_parcels(self):
|
||||
""" Updates underlying parcel information
|
||||
|
||||
|
||||
@@ -39,7 +39,17 @@ class District(UuidModel, AdministrativeSpatialReference):
|
||||
""" The model District refers to "Kreis"
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=[
|
||||
"key",
|
||||
"name",
|
||||
],
|
||||
name="Unique district constraint"
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class Municipal(UuidModel, AdministrativeSpatialReference):
|
||||
@@ -53,6 +63,18 @@ class Municipal(UuidModel, AdministrativeSpatialReference):
|
||||
blank=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=[
|
||||
"key",
|
||||
"name",
|
||||
"district",
|
||||
],
|
||||
name="Unique municipal constraint"
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class ParcelGroup(UuidModel, AdministrativeSpatialReference):
|
||||
""" The model ParcelGroup refers to "Gemarkung", which is defined as a loose group of parcels
|
||||
@@ -65,6 +87,18 @@ class ParcelGroup(UuidModel, AdministrativeSpatialReference):
|
||||
blank=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=[
|
||||
"key",
|
||||
"name",
|
||||
"municipal",
|
||||
],
|
||||
name="Unique parcel group constraint"
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
class Parcel(UuidModel):
|
||||
""" The Parcel model holds administrative data on covered properties.
|
||||
@@ -106,6 +140,21 @@ class Parcel(UuidModel):
|
||||
)
|
||||
updated_on = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
constraints = [
|
||||
models.UniqueConstraint(
|
||||
fields=[
|
||||
"district",
|
||||
"municipal",
|
||||
"parcel_group",
|
||||
"flr",
|
||||
"flrstck_nnr",
|
||||
"flrstck_zhlr",
|
||||
],
|
||||
name="Unique parcel constraint"
|
||||
)
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.parcel_group} | {self.flr} | {self.flrstck_zhlr} | {self.flrstck_nnr}"
|
||||
|
||||
|
||||
@@ -6,9 +6,11 @@ Created on: 26.10.21
|
||||
|
||||
"""
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID
|
||||
from ema.models import Ema
|
||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
||||
from user.models import User, Team
|
||||
from django.contrib.auth.models import Group
|
||||
from django.contrib.gis.geos import MultiPolygon, Polygon
|
||||
@@ -287,8 +289,28 @@ class BaseTestCase(TestCase):
|
||||
"""
|
||||
polygon = Polygon.from_bbox((7.592449, 50.359385, 7.593382, 50.359874))
|
||||
polygon.srid = 4326
|
||||
polygon = polygon.transform(3857, clone=True)
|
||||
return MultiPolygon(polygon, srid=3857) # 3857 is the default srid used for MultiPolygonField in the form
|
||||
polygon = polygon.transform(DEFAULT_SRID_RLP, clone=True)
|
||||
return MultiPolygon(polygon, srid=DEFAULT_SRID_RLP)
|
||||
|
||||
def create_geojson(self, geometry):
|
||||
""" Creates a default structure including geojson from a geometry
|
||||
|
||||
Args:
|
||||
geometry ():
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
geom_json = {
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": json.loads(geometry.geojson),
|
||||
}
|
||||
]
|
||||
}
|
||||
geom_json = json.dumps(geom_json)
|
||||
return geom_json
|
||||
|
||||
def create_dummy_handler(self) -> Handler:
|
||||
""" Creates a Handler
|
||||
|
||||
Reference in New Issue
Block a user