From 4f6e9022857a08c5fae4e43124e40b6e9d1ab260 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Fri, 18 Feb 2022 11:22:38 +0100 Subject: Geodata redesign: operation migrations (2/2) --- .../management/commands/migrate_to_geo_v4.py | 97 ++++++++++------ .../migrations/0220_auto_20220214_1920.py | 124 -------------------- .../migrations/0220_auto_20220218_1049.py | 128 +++++++++++++++++++++ ishtar_common/models_common.py | 2 +- ishtar_common/utils.py | 4 + 5 files changed, 197 insertions(+), 158 deletions(-) delete mode 100644 ishtar_common/migrations/0220_auto_20220214_1920.py create mode 100644 ishtar_common/migrations/0220_auto_20220218_1049.py (limited to 'ishtar_common') diff --git a/ishtar_common/management/commands/migrate_to_geo_v4.py b/ishtar_common/management/commands/migrate_to_geo_v4.py index df275bd85..64ab25c16 100644 --- a/ishtar_common/management/commands/migrate_to_geo_v4.py +++ b/ishtar_common/management/commands/migrate_to_geo_v4.py @@ -62,43 +62,74 @@ def migrate(quiet=False, log=True): ) q = Operation.objects.exclude(main_geodata__isnull=False) nb = q.count() + data_type_area, __ = models_common.GeoDataType.objects.get_or_create( + txt_idx="operation-area", defaults={"label": "Emprise de l'opération"} + ) + data_type_center, __ = models_common.GeoDataType.objects.get_or_create( + txt_idx="operation-center", defaults={"label": "Centre de l'opération"} + ) for idx, operation in enumerate(q.all()): - if operation.multi_polygon_source == "T": - operation._no_move = True - operation.skip_history_when_saving = True - operation.save() # auto managed - elif operation.multi_polygon_source == "P": - # TODO - - """ - q = operation.towns.filter(limit__isnull=False) - nb = q.count - if not nb: - break - elif nb == 1: - town = q.all()[0] - geo = models_common.GeoVectorData.objects.get( - source_content_type=town_content_type, - source_id=town.pk - ) - else: + if not quiet: + sys.stdout.write(f"\r[{percent(idx, nb)}] Migrate operations {idx + 1}/{nb}") + sys.stdout.flush() + operation._no_move = True + operation.skip_history_when_saving = True + operation.save() # auto manage geo town association + q_towns = operation.towns.filter(main_geodata__multi_polygon__isnull=False) + if q_towns.count() > 1: + changed.append( + ["operation", str(operation), operation.pk, + "Association géo de zone communale"]) + elif q_towns.count() == 1: + changed.append( + ["operation", str(operation), operation.pk, + "Association géo de commune"]) + if operation.multi_polygon_source == "P" and operation.multi_polygon: + attrs = { + "name": f"{_('Operation')}{_(':')} {str(operation)}", + "source_content_type": operation_content_type, + "source_id": operation.pk, + "multi_polygon": operation.multi_polygon, + "data_type": data_type_area, + } + data = models_common.GeoVectorData.objects.create(**attrs) + operation.main_geodata = data + operation.save() + changed.append( + ["geovectordata", data.name, data.pk, "Multi-polygone opération"]) + if operation.point_source == "P" and operation.point_2d: + if operation.x and operation.y: attrs = { - "name": name, - "source_content_type": town_content_type, - "source_id": town.pk, - "data_type": data_type, - "provider": provider, - "multi_polygon": poly, + "name": f"{_('Operation')}{_(':')} {str(operation)}", + "source_content_type": operation_content_type, + "source_id": operation.pk, + "data_type": data_type_center, + "x": operation.x, + "y": operation.y, + "z": operation.z, } - geo, created = models_common.GeoVectorData.objects.get_or_create( - **attrs) - - operation.main_geodata = geo - operation.skip_history_when_saving = True - operation._no_move = True - operation.save() - """ + data = models_common.GeoVectorData.objects.create(**attrs) + operation.main_geodata = data + operation.save() + changed.append( + ["geovectordata", data.name, data.pk, "Coordonnées opération"]) + elif operation.point_2d: + attrs = { + "name": f"{_('Operation')}{_(':')} {str(operation)}", + "source_content_type": operation_content_type, + "source_id": operation.pk, + "data_type": data_type_center, + } + if operation.point: + attrs["point_3d"] = operation.point + else: + attrs["point_2d"] = operation.point_2d + data = models_common.GeoVectorData.objects.create(**attrs) + operation.main_geodata = data + operation.save() + changed.append( + ["geovectordata", data.name, data.pk, "Point opération"]) if log and changed: diff --git a/ishtar_common/migrations/0220_auto_20220214_1920.py b/ishtar_common/migrations/0220_auto_20220214_1920.py deleted file mode 100644 index 2f40eab00..000000000 --- a/ishtar_common/migrations/0220_auto_20220214_1920.py +++ /dev/null @@ -1,124 +0,0 @@ -# Generated by Django 2.2.24 on 2022-02-14 19:20 - -import django.contrib.gis.db.models.fields -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion -import ishtar_common.models_common -import re - - -class Migration(migrations.Migration): - - dependencies = [ - ('contenttypes', '0002_remove_content_type_name'), - ('ishtar_common', '0219_auto_20220120_1552'), - ] - - operations = [ - migrations.CreateModel( - name='GeoDataType', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('label', models.TextField(verbose_name='Label')), - ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), - ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), - ('available', models.BooleanField(default=True, verbose_name='Available')), - ('order', models.IntegerField(default=10, verbose_name='Order')), - ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.GeoDataType', verbose_name='Parent')), - ], - options={ - 'verbose_name': 'Geographic - Data type', - 'verbose_name_plural': 'Geographic - Data types', - 'ordering': ('order', 'label'), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='GeoOriginType', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('label', models.TextField(verbose_name='Label')), - ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), - ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), - ('available', models.BooleanField(default=True, verbose_name='Available')), - ('order', models.IntegerField(default=10, verbose_name='Order')), - ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.GeoOriginType', verbose_name='Parent')), - ], - options={ - 'verbose_name': 'Geographic - Origin type', - 'verbose_name_plural': 'Geographic - Origin types', - 'ordering': ('order', 'label'), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.CreateModel( - name='GeoProviderType', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('label', models.TextField(verbose_name='Label')), - ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), - ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), - ('available', models.BooleanField(default=True, verbose_name='Available')), - ('order', models.IntegerField(default=10, verbose_name='Order')), - ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.GeoProviderType', verbose_name='Parent')), - ], - options={ - 'verbose_name': 'Geographic - Provider type', - 'verbose_name_plural': 'Geographic - Provider types', - 'ordering': ('order', 'label'), - }, - bases=(ishtar_common.models_common.Cached, models.Model), - ), - migrations.AlterModelOptions( - name='person', - options={'ordering': ['name', 'surname'], 'permissions': (('view_own_person', 'Can view own Person'), ('add_own_person', 'Can add own Person'), ('change_own_person', 'Can change own Person'), ('delete_own_person', 'Can delete own Person')), 'verbose_name': 'Person', 'verbose_name_plural': 'Persons'}, - ), - migrations.AlterModelOptions( - name='spatialreferencesystem', - options={'ordering': ('order', 'label'), 'verbose_name': 'Spatial reference system', 'verbose_name_plural': 'Spatial reference systems'}, - ), - migrations.CreateModel( - name='GeoVectorData', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(default='Default', max_length=200, verbose_name='Name')), - ('source_id', models.PositiveIntegerField()), - ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), - ('x', models.FloatField(blank=True, help_text='User input', null=True, verbose_name='X')), - ('y', models.FloatField(blank=True, help_text='User input', null=True, verbose_name='Y')), - ('z', models.FloatField(blank=True, help_text='User input', null=True, verbose_name='Z')), - ('cached_x', models.FloatField(blank=True, null=True, verbose_name='X (cached)')), - ('cached_y', models.FloatField(blank=True, null=True, verbose_name='Y (cached)')), - ('cached_z', models.FloatField(blank=True, null=True, verbose_name='Z (cached)')), - ('estimated_error_x', models.FloatField(blank=True, null=True, verbose_name='Estimated error for X')), - ('estimated_error_y', models.FloatField(blank=True, null=True, verbose_name='Estimated error for Y')), - ('estimated_error_z', models.FloatField(blank=True, null=True, verbose_name='Estimated error for Z')), - ('point_2d', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Point (2D)')), - ('point_3d', django.contrib.gis.db.models.fields.PointField(blank=True, dim=3, null=True, srid=4326, verbose_name='Point (3D)')), - ('multi_points', django.contrib.gis.db.models.fields.MultiPointField(blank=True, null=True, srid=4326, verbose_name='Multi points')), - ('multi_line', django.contrib.gis.db.models.fields.MultiLineStringField(blank=True, null=True, srid=4326, verbose_name='Multi line')), - ('multi_polygon', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Multi polygon')), - ('need_update', models.BooleanField(default=False, verbose_name='Need update')), - ('data_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.GeoDataType', verbose_name='Data type')), - ('origin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.GeoOriginType', verbose_name='Origin')), - ('provider', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.GeoProviderType', verbose_name='Provider')), - ('source_content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='content_type_geovectordata', to='contenttypes.ContentType')), - ('spatial_reference_system', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.SpatialReferenceSystem', verbose_name='Spatial Reference System')), - ], - options={ - 'verbose_name': 'Geographic - Vector data', - 'verbose_name_plural': 'Geographic - Vector data', - }, - ), - migrations.AddField( - model_name='town', - name='geodata', - field=models.ManyToManyField(blank=True, related_name='related_items_ishtar_common_town', to='ishtar_common.GeoVectorData'), - ), - migrations.AddField( - model_name='town', - name='main_geodata', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='main_related_items_ishtar_common_town', to='ishtar_common.GeoVectorData'), - ), - ] diff --git a/ishtar_common/migrations/0220_auto_20220218_1049.py b/ishtar_common/migrations/0220_auto_20220218_1049.py new file mode 100644 index 000000000..2c64c3e29 --- /dev/null +++ b/ishtar_common/migrations/0220_auto_20220218_1049.py @@ -0,0 +1,128 @@ +# Generated by Django 2.2.24 on 2022-02-18 10:49 + +import django.contrib.gis.db.models.fields +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import ishtar_common.models_common +import re + + +class Migration(migrations.Migration): + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('ishtar_common', '0219_auto_20220120_1552'), + ] + + operations = [ + migrations.CreateModel( + name='GeoDataType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.TextField(verbose_name='Label')), + ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('available', models.BooleanField(default=True, verbose_name='Available')), + ('order', models.IntegerField(default=10, verbose_name='Order')), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.GeoDataType', verbose_name='Parent')), + ], + options={ + 'verbose_name': 'Geographic - Data type', + 'verbose_name_plural': 'Geographic - Data types', + 'ordering': ('order', 'label'), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='GeoOriginType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.TextField(verbose_name='Label')), + ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('available', models.BooleanField(default=True, verbose_name='Available')), + ('order', models.IntegerField(default=10, verbose_name='Order')), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.GeoOriginType', verbose_name='Parent')), + ], + options={ + 'verbose_name': 'Geographic - Origin type', + 'verbose_name_plural': 'Geographic - Origin types', + 'ordering': ('order', 'label'), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.CreateModel( + name='GeoProviderType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('label', models.TextField(verbose_name='Label')), + ('txt_idx', models.TextField(help_text='The slug is the standardized version of the name. It contains only lowercase letters, numbers and hyphens. Each slug must be unique.', unique=True, validators=[django.core.validators.RegexValidator(re.compile('^[-a-zA-Z0-9_]+\\Z'), "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.", 'invalid')], verbose_name='Textual ID')), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('available', models.BooleanField(default=True, verbose_name='Available')), + ('order', models.IntegerField(default=10, verbose_name='Order')), + ('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='ishtar_common.GeoProviderType', verbose_name='Parent')), + ], + options={ + 'verbose_name': 'Geographic - Provider type', + 'verbose_name_plural': 'Geographic - Provider types', + 'ordering': ('order', 'label'), + }, + bases=(ishtar_common.models_common.Cached, models.Model), + ), + migrations.AlterModelOptions( + name='area', + options={'ordering': ('label',), 'verbose_name': 'Town - Area', 'verbose_name_plural': 'Town - Areas'}, + ), + migrations.AlterModelOptions( + name='person', + options={'ordering': ['name', 'surname'], 'permissions': (('view_own_person', 'Can view own Person'), ('add_own_person', 'Can add own Person'), ('change_own_person', 'Can change own Person'), ('delete_own_person', 'Can delete own Person')), 'verbose_name': 'Person', 'verbose_name_plural': 'Persons'}, + ), + migrations.AlterModelOptions( + name='spatialreferencesystem', + options={'ordering': ('order', 'label'), 'verbose_name': 'Spatial reference system', 'verbose_name_plural': 'Spatial reference systems'}, + ), + migrations.CreateModel( + name='GeoVectorData', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.TextField(default='Default', verbose_name='Name')), + ('source_id', models.PositiveIntegerField()), + ('comment', models.TextField(blank=True, default='', verbose_name='Comment')), + ('x', models.FloatField(blank=True, help_text='User input', null=True, verbose_name='X')), + ('y', models.FloatField(blank=True, help_text='User input', null=True, verbose_name='Y')), + ('z', models.FloatField(blank=True, help_text='User input', null=True, verbose_name='Z')), + ('cached_x', models.FloatField(blank=True, null=True, verbose_name='X (cached)')), + ('cached_y', models.FloatField(blank=True, null=True, verbose_name='Y (cached)')), + ('cached_z', models.FloatField(blank=True, null=True, verbose_name='Z (cached)')), + ('estimated_error_x', models.FloatField(blank=True, null=True, verbose_name='Estimated error for X')), + ('estimated_error_y', models.FloatField(blank=True, null=True, verbose_name='Estimated error for Y')), + ('estimated_error_z', models.FloatField(blank=True, null=True, verbose_name='Estimated error for Z')), + ('point_2d', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Point (2D)')), + ('point_3d', django.contrib.gis.db.models.fields.PointField(blank=True, dim=3, null=True, srid=4326, verbose_name='Point (3D)')), + ('multi_points', django.contrib.gis.db.models.fields.MultiPointField(blank=True, null=True, srid=4326, verbose_name='Multi points')), + ('multi_line', django.contrib.gis.db.models.fields.MultiLineStringField(blank=True, null=True, srid=4326, verbose_name='Multi line')), + ('multi_polygon', django.contrib.gis.db.models.fields.MultiPolygonField(blank=True, null=True, srid=4326, verbose_name='Multi polygon')), + ('need_update', models.BooleanField(default=False, verbose_name='Need update')), + ('data_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.GeoDataType', verbose_name='Data type')), + ('origin', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.GeoOriginType', verbose_name='Origin')), + ('provider', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.GeoProviderType', verbose_name='Provider')), + ('source_content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='content_type_geovectordata', to='contenttypes.ContentType')), + ('spatial_reference_system', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ishtar_common.SpatialReferenceSystem', verbose_name='Spatial Reference System')), + ], + options={ + 'verbose_name': 'Geographic - Vector data', + 'verbose_name_plural': 'Geographic - Vector data', + }, + ), + migrations.AddField( + model_name='town', + name='geodata', + field=models.ManyToManyField(blank=True, related_name='related_items_ishtar_common_town', to='ishtar_common.GeoVectorData'), + ), + migrations.AddField( + model_name='town', + name='main_geodata', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='main_related_items_ishtar_common_town', to='ishtar_common.GeoVectorData'), + ), + ] diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py index 95ceee948..9aae922cc 100644 --- a/ishtar_common/models_common.py +++ b/ishtar_common/models_common.py @@ -2063,7 +2063,7 @@ class GeoProviderType(HierarchicalType): class GeoVectorData(models.Model): - name = models.CharField(_("Name"), default=_("Default"), max_length=200) + name = models.TextField(_("Name"), default=_("Default")) source_content_type = models.ForeignKey( ContentType, related_name="content_type_geovectordata", on_delete=models.CASCADE ) diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index 02eeff93c..53727b6d3 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -774,6 +774,7 @@ def _post_save_geodata(sender, **kwargs): modified = True # managed cached coordinates + # TODO cached_x, cached_y, cached_z = None, None, None coords = instance.display_coordinates(rounded=False, dim=3) @@ -845,6 +846,9 @@ def _post_save_geo(sender, **kwargs): if not instance: return + return + # TODO to delete + kls_name = instance.__class__.__name__ if not profile.locate_warehouses and ( -- cgit v1.2.3