# Parcel duplicate repair
* adds mechanic to repair parcels in case of unwanted parcel duplicates * optimizes filtering of geometries for parcel recalculation
This commit is contained in:
		
							parent
							
								
									8ef11c681e
								
							
						
					
					
						commit
						7820dec3d1
					
				@ -8,11 +8,9 @@ Created on: 04.01.22
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.contrib.gis.db.models.functions import Area
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.utils.timezone import now
 | 
			
		||||
 | 
			
		||||
from konova.management.commands.setup import BaseKonovaCommand
 | 
			
		||||
from konova.models import Geometry
 | 
			
		||||
from konova.models import Geometry, ParcelIntersection
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Command(BaseKonovaCommand):
 | 
			
		||||
@ -36,17 +34,21 @@ class Command(BaseKonovaCommand):
 | 
			
		||||
    def recalculate_parcels(self, options: dict):
 | 
			
		||||
        force_all = options.get("force_all", False)
 | 
			
		||||
 | 
			
		||||
        if force_all:
 | 
			
		||||
            geometry_objects = Geometry.objects.all()
 | 
			
		||||
        else:
 | 
			
		||||
            _today = now().date()
 | 
			
		||||
            _date_threshold = _today - datetime.timedelta(days=1)
 | 
			
		||||
            geometry_objects = Geometry.objects.filter(
 | 
			
		||||
                Q(
 | 
			
		||||
                    Q(parcel_update_start__date__lte=_date_threshold) |
 | 
			
		||||
                    Q(parcel_update_start__isnull=True)
 | 
			
		||||
                ),
 | 
			
		||||
                parcel_update_end__isnull=True
 | 
			
		||||
        geometry_objects = Geometry.objects.all()
 | 
			
		||||
 | 
			
		||||
        if not force_all:
 | 
			
		||||
            # Fetch all intersections
 | 
			
		||||
            intersection_objs = ParcelIntersection.objects.filter(
 | 
			
		||||
                geometry__in=geometry_objects
 | 
			
		||||
            )
 | 
			
		||||
            # Just take the geometry ids, which seem to have intersections
 | 
			
		||||
            geom_with_intersection_ids = intersection_objs.values_list(
 | 
			
		||||
                "geometry__id",
 | 
			
		||||
                flat=True
 | 
			
		||||
            )
 | 
			
		||||
            # Filter those geometries out (they have intersections and do not need to be processed)
 | 
			
		||||
            geometry_objects = geometry_objects.exclude(
 | 
			
		||||
                id__in=geom_with_intersection_ids
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        self._write_warning("=== Update parcels and districts ===")
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ Created on: 15.11.21
 | 
			
		||||
import json
 | 
			
		||||
 | 
			
		||||
from django.contrib.gis.db.models import MultiPolygonField
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
 | 
			
		||||
from django.db import models, transaction
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
 | 
			
		||||
@ -223,6 +223,17 @@ class Geometry(BaseResource):
 | 
			
		||||
                )
 | 
			
		||||
                parcel_obj.updated_on = _now
 | 
			
		||||
                parcels_to_update.append(parcel_obj)
 | 
			
		||||
            except MultipleObjectsReturned:
 | 
			
		||||
                parcel_obj = Parcel.make_unique(
 | 
			
		||||
                    district=district,
 | 
			
		||||
                    municipal=municipal,
 | 
			
		||||
                    parcel_group=parcel_group,
 | 
			
		||||
                    flr=flr_val,
 | 
			
		||||
                    flrstck_nnr=flrstck_nnr,
 | 
			
		||||
                    flrstck_zhlr=flrstck_zhlr,
 | 
			
		||||
                )
 | 
			
		||||
                parcel_obj.updated_on = _now
 | 
			
		||||
                parcels_to_update.append(parcel_obj)
 | 
			
		||||
            except ObjectDoesNotExist:
 | 
			
		||||
                # If not existing, create object but do not commit, yet
 | 
			
		||||
                parcel_obj = Parcel(
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 16.12.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.db import models, transaction
 | 
			
		||||
 | 
			
		||||
from konova.models import UuidModel
 | 
			
		||||
 | 
			
		||||
@ -158,6 +158,46 @@ class Parcel(UuidModel):
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return f"{self.parcel_group} | {self.flr} | {self.flrstck_zhlr} | {self.flrstck_nnr}"
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    @transaction.atomic
 | 
			
		||||
    def make_unique(cls, **kwargs):
 | 
			
		||||
        """ Checks for duplicates of a Parcel, choose a (now) unique one,
 | 
			
		||||
        repairs relations for ParcelIntersection and removes duplicates.
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            **kwargs ():
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            unique_true (Parcel): The new unique 'true one'
 | 
			
		||||
        """
 | 
			
		||||
        parcel_objs = Parcel.objects.filter(**kwargs)
 | 
			
		||||
 | 
			
		||||
        if not parcel_objs.exists():
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        # Get one of the found parcels and use it as new 'true one'
 | 
			
		||||
        unique_parcel = parcel_objs.first()
 | 
			
		||||
        # separate it from the rest
 | 
			
		||||
        parcel_objs = parcel_objs.exclude(id=unique_parcel.id)
 | 
			
		||||
 | 
			
		||||
        if not parcel_objs.exists():
 | 
			
		||||
            # There are no duplicates - all good, just return
 | 
			
		||||
            return unique_parcel
 | 
			
		||||
 | 
			
		||||
        # Fetch existing intersections, which still point on the duplicated parcels
 | 
			
		||||
        intersection_objs = ParcelIntersection.objects.filter(
 | 
			
		||||
            parcel__in=parcel_objs
 | 
			
		||||
        )
 | 
			
		||||
        # Change each intersection, so they point on the 'true one' parcel from now on
 | 
			
		||||
        for intersection in intersection_objs:
 | 
			
		||||
            intersection.parcel = unique_parcel
 | 
			
		||||
            intersection.save()
 | 
			
		||||
 | 
			
		||||
        # Remove the duplicated parcels
 | 
			
		||||
        parcel_objs.delete()
 | 
			
		||||
 | 
			
		||||
        return unique_parcel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParcelIntersection(UuidModel):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user