diff --git a/konova/models/geometry.py b/konova/models/geometry.py index f216903..79a27e0 100644 --- a/konova/models/geometry.py +++ b/konova/models/geometry.py @@ -13,6 +13,7 @@ from django.utils import timezone from konova.models import BaseResource, UuidModel from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP +from konova.utils.schneider.fetcher import ParcelFetcher from konova.utils.wfs.spatial import ParcelWFSFetcher @@ -109,8 +110,8 @@ class Geometry(BaseResource): return objs @transaction.atomic - def update_parcels(self): - """ Updates underlying parcel information + def update_parcels_wfs(self): + """ Updates underlying parcel information using the WFS of LVermGeo Returns: @@ -185,6 +186,79 @@ class Geometry(BaseResource): ["calculated_on"] ) + def update_parcels(self): + """ Updates underlying parcel information + + Returns: + + """ + from konova.models import Parcel, District, ParcelIntersection, Municipal, ParcelGroup + + if self.geom.empty: + # Nothing to do + return + + parcel_fetcher = ParcelFetcher( + geometry=self + ) + fetched_parcels = parcel_fetcher.get_parcels() + + _now = timezone.now() + underlying_parcels = [] + for result in fetched_parcels: + # There could be parcels which include the word 'Flur', + # which needs to be deleted and just keep the numerical values + ## THIS CAN BE REMOVED IN THE FUTURE, WHEN 'Flur' WON'T OCCUR ANYMORE! + flr_val = result["flur"].replace("Flur ", "") + district = District.objects.get_or_create( + key=result["kreisschl"], + name=result["kreis"], + )[0] + municipal = Municipal.objects.get_or_create( + key=result["gmdschl"], + name=result["gemeinde"], + district=district, + )[0] + parcel_group = ParcelGroup.objects.get_or_create( + key=result["gemaschl"], + name=result["gemarkung"], + municipal=municipal, + )[0] + flrstck_nnr = result['flstnrnen'] + if not flrstck_nnr: + flrstck_nnr = None + flrstck_zhlr = result['flstnrzae'] + if not flrstck_zhlr: + flrstck_zhlr = None + parcel_obj = Parcel.objects.get_or_create( + district=district, + municipal=municipal, + parcel_group=parcel_group, + flr=flr_val, + flrstck_nnr=flrstck_nnr, + flrstck_zhlr=flrstck_zhlr, + )[0] + parcel_obj.district = district + parcel_obj.updated_on = _now + parcel_obj.save() + underlying_parcels.append(parcel_obj) + + # Update the linked parcels + self.parcels.clear() + self.parcels.set(underlying_parcels) + + # Set the calculated_on intermediate field, so this related data will be found on lookups + intersections_without_ts = self.parcelintersection_set.filter( + parcel__in=self.parcels.all(), + calculated_on__isnull=True, + ) + for entry in intersections_without_ts: + entry.calculated_on = _now + ParcelIntersection.objects.bulk_update( + intersections_without_ts, + ["calculated_on"] + ) + def get_underlying_parcels(self): """ Getter for related parcels and their districts diff --git a/konova/sub_settings/schneider_settings.py b/konova/sub_settings/schneider_settings.py new file mode 100644 index 0000000..caf4ec2 --- /dev/null +++ b/konova/sub_settings/schneider_settings.py @@ -0,0 +1,11 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 14.12.22 + +""" + +base_url = "http://127.0.0.1:8002" +auth_header = "auth" +auth_header_token = "CHANGE_ME" diff --git a/konova/utils/schneider/fetcher.py b/konova/utils/schneider/fetcher.py new file mode 100644 index 0000000..0bc87f7 --- /dev/null +++ b/konova/utils/schneider/fetcher.py @@ -0,0 +1,59 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 14.12.22 + +""" +import json +from json import JSONDecodeError + +import requests + +from konova.sub_settings import schneider_settings + + +class ParcelFetcher: + base_url = schneider_settings.base_url + auth_header = schneider_settings.auth_header + auth_header_token = schneider_settings.auth_header_token + + geometry = None + geojson = None + results = None + + def __init__(self, geometry): + if geometry is None: + raise AssertionError("Geometry must not be none") + self.geometry = geometry + + # Reduce size of geometry to avoid "intersections" because of exact border matching + geom = geometry.geom.buffer(-0.001) + self.geojson = geom.ewkt + self.results = [] + + def get_parcels(self, url: str = None): + post_url = url + if post_url is None: + post_url = f"{self.base_url}/parcel/intersect/" + + response = requests.post( + url=post_url, + data=self.geojson, + headers={ + self.auth_header: self.auth_header_token + } + ) + + try: + content = json.loads(response.content.decode("utf-8")) + except JSONDecodeError: + content = {} + next = content.get("next", None) + fetched_parcels = content.get("results", []) + self.results += fetched_parcels + + if next: + self.get_parcels(next) + + return self.results \ No newline at end of file