summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2026-03-27 13:04:29 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2026-04-01 10:58:25 +0200
commit5df83f7aa54a3ecbbc957d52babf4b52b9e22706 (patch)
treec977a80e1974f152caa72235902d10b5c2eef3fa
parent1b1925afbcc381df1fbbb6f8b8488683f17378a4 (diff)
downloadIshtar-5df83f7aa54a3ecbbc957d52babf4b52b9e22706.tar.bz2
Ishtar-5df83f7aa54a3ecbbc957d52babf4b52b9e22706.zip
🗃️ sites - models migrations: heritage, relations and datings fields
-rw-r--r--archaeological_operations/migrations/0126_archaeologicalsite_heritage_relations_datings.py207
-rw-r--r--archaeological_operations/migrations/0127_data_migration_current_states.py23
-rw-r--r--ishtar_common/migrations/0274_qualifiedbiographicalnote.py6
-rw-r--r--ishtar_common/models.py9
4 files changed, 245 insertions, 0 deletions
diff --git a/archaeological_operations/migrations/0126_archaeologicalsite_heritage_relations_datings.py b/archaeological_operations/migrations/0126_archaeologicalsite_heritage_relations_datings.py
new file mode 100644
index 000000000..baa407d6f
--- /dev/null
+++ b/archaeological_operations/migrations/0126_archaeologicalsite_heritage_relations_datings.py
@@ -0,0 +1,207 @@
+# Generated by Django 4.2.19 on 2026-03-27 12:03
+
+import django.core.validators
+from django.db import migrations, models
+import django.db.models.deletion
+import ishtar_common.models_common
+import re
+import uuid
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0275_authortype_parent'),
+ ('archaeological_context_records', '0126_migrate_periods_and_datings'),
+ ('archaeological_operations', '0125_archaeologicalsite_actors'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='cached_current_states',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached current states label'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='cached_heritage_environmental_protections',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached heritage and environmental protections label'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='cached_heritage_interests',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached heritage interests label'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='current_states',
+ field=models.ManyToManyField(blank=True, to='archaeological_operations.sitecurrentstatustype', verbose_name='Current status'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='details_on_protection',
+ field=models.TextField(blank=True, default='', verbose_name='Details on protection'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='editors',
+ field=models.ManyToManyField(blank=True, related_name='sites', to='ishtar_common.author', verbose_name='Editors'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='protection_date',
+ field=models.DateField(blank=True, null=True, verbose_name='Protection date'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='protection_id',
+ field=models.TextField(blank=True, default='', verbose_name='Protection ID'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='cached_current_states',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached current states label'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='cached_heritage_environmental_protections',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached heritage and environmental protections label'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='cached_heritage_interests',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached heritage interests label'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='details_on_protection',
+ field=models.TextField(blank=True, default='', verbose_name='Details on protection'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='protection_date',
+ field=models.DateField(blank=True, null=True, verbose_name='Protection date'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='protection_id',
+ field=models.TextField(blank=True, default='', verbose_name='Protection ID'),
+ ),
+ migrations.AlterField(
+ model_name='archaeologicalsite',
+ name='current_status',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sites_deprecated', to='archaeological_operations.sitecurrentstatustype', verbose_name='Current status - deprecated'),
+ ),
+ migrations.AlterField(
+ model_name='historicalarchaeologicalsite',
+ name='current_status',
+ field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='archaeological_operations.sitecurrentstatustype', verbose_name='Current status - deprecated'),
+ ),
+ migrations.CreateModel(
+ name='SiteRelationType',
+ 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=1, verbose_name='Order')),
+ ('symmetrical', models.BooleanField(verbose_name='Symmetrical')),
+ ('tiny_label', models.CharField(blank=True, max_length=50, null=True, verbose_name='Tiny label')),
+ ('logical_relation', models.CharField(blank=True, choices=[('above', 'Above'), ('below', 'Below'), ('equal', 'Equal'), ('include', 'Include'), ('included', 'Is included')], max_length=10, null=True, verbose_name='Logical relation')),
+ ('inverse_relation', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_operations.siterelationtype', verbose_name='Inverse relation')),
+ ],
+ options={
+ 'verbose_name': 'Site relation type',
+ 'verbose_name_plural': 'Site relation types',
+ 'ordering': ('order', 'label'),
+ },
+ bases=(ishtar_common.models_common.Cached, models.Model),
+ ),
+ migrations.CreateModel(
+ name='SiteRecordRelations',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('timestamp_geo', models.IntegerField(blank=True, null=True, verbose_name='Timestamp geo')),
+ ('timestamp_label', models.IntegerField(blank=True, null=True, verbose_name='Timestamp label')),
+ ('imports', models.ManyToManyField(blank=True, related_name='imported_%(app_label)s_%(class)s', to='ishtar_common.import', verbose_name='Created by imports')),
+ ('imports_updated', models.ManyToManyField(blank=True, related_name='import_updated_%(app_label)s_%(class)s', to='ishtar_common.import', verbose_name='Updated by imports')),
+ ('left_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='right_relations', to='archaeological_operations.archaeologicalsite')),
+ ('relation_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='archaeological_operations.siterelationtype')),
+ ('right_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='left_relations', to='archaeological_operations.archaeologicalsite')),
+ ],
+ options={
+ 'verbose_name': 'Site record relation',
+ 'verbose_name_plural': 'Site record relations',
+ 'ordering': ('left_record__cached_label', 'relation_type', 'right_record__cached_label'),
+ 'permissions': [('view_siterelation', 'Can view all Site relations')],
+ },
+ ),
+ migrations.CreateModel(
+ name='SiteDating',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('uuid', models.UUIDField(default=uuid.uuid4)),
+ ('reference', models.TextField(blank=True, default='', verbose_name='Reference')),
+ ('external_id', models.TextField(blank=True, default='', verbose_name='External ID')),
+ ('start_date', models.IntegerField(blank=True, null=True, verbose_name='Start date')),
+ ('end_date', models.IntegerField(blank=True, null=True, verbose_name='End date')),
+ ('precise_dating', models.TextField(blank=True, default='', verbose_name='Precise on this dating')),
+ ('dating_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_context_records.datingtype', verbose_name='Dating type')),
+ ('period', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='archaeological_operations.period', verbose_name='Chronological period')),
+ ('quality', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='archaeological_context_records.datingquality', verbose_name='Quality')),
+ ('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='datings', to='archaeological_operations.archaeologicalsite', verbose_name='Site')),
+ ],
+ options={
+ 'verbose_name': 'Site dating',
+ 'verbose_name_plural': 'Site datings',
+ },
+ bases=(models.Model, ishtar_common.models_common.SerializeItem),
+ ),
+ migrations.CreateModel(
+ name='HeritageInterestType',
+ 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='archaeological_operations.heritageinteresttype', verbose_name='Parent')),
+ ],
+ options={
+ 'verbose_name': 'Heritage interest type',
+ 'verbose_name_plural': 'Heritage interest types',
+ 'ordering': ('order', 'label'),
+ },
+ bases=(ishtar_common.models_common.Cached, models.Model),
+ ),
+ migrations.CreateModel(
+ name='HeritageAndEnvironmentalProtectionType',
+ 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='archaeological_operations.heritageandenvironmentalprotectiontype', verbose_name='Parent')),
+ ],
+ options={
+ 'verbose_name': 'Heritage and environmental protection type',
+ 'verbose_name_plural': 'Heritage and environmental protection types',
+ 'ordering': ('order', 'label'),
+ },
+ bases=(ishtar_common.models_common.Cached, models.Model),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='heritage_environmental_protections',
+ field=models.ManyToManyField(blank=True, to='archaeological_operations.heritageandenvironmentalprotectiontype', verbose_name='Heritage and environmental protections'),
+ ),
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='heritage_interests',
+ field=models.ManyToManyField(blank=True, to='archaeological_operations.heritageinteresttype', verbose_name='Heritage interests'),
+ ),
+ ]
diff --git a/archaeological_operations/migrations/0127_data_migration_current_states.py b/archaeological_operations/migrations/0127_data_migration_current_states.py
new file mode 100644
index 000000000..fe1aa5c25
--- /dev/null
+++ b/archaeological_operations/migrations/0127_data_migration_current_states.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.2.19 on 2026-03-27 12:06
+
+from django.db import migrations
+
+
+def migrate_current_states(apps, __):
+ ArchaeologicalSite = apps.get_model("archaeological_operations", "archaeologicalsite")
+ if not hasattr(ArchaeologicalSite, "current_status"):
+ return
+ q = ArchaeologicalSite.objects.filter(current_status__isnull=False)
+ for site in q.all():
+ site.current_states.add(site.current_status)
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_operations', '0126_archaeologicalsite_heritage_relations_datings'),
+ ]
+
+ operations = [
+ migrations.RunPython(migrate_current_states)
+ ]
diff --git a/ishtar_common/migrations/0274_qualifiedbiographicalnote.py b/ishtar_common/migrations/0274_qualifiedbiographicalnote.py
index e27fbfdeb..7f23586c9 100644
--- a/ishtar_common/migrations/0274_qualifiedbiographicalnote.py
+++ b/ishtar_common/migrations/0274_qualifiedbiographicalnote.py
@@ -80,4 +80,10 @@ class Migration(migrations.Migration):
name='export_format',
field=models.CharField(blank=True, choices=[('docx', 'DOCX'), ('html', 'HTML'), ('pdf', 'PDF'), ('xlsx', 'XLSX')], default='', max_length=4, verbose_name='Export format'),
),
+ migrations.AddField(
+ model_name='qualifiedbiographicalnotetype',
+ name='model',
+ field=models.CharField(choices=[('S', 'Archaeological site'), ('O', 'Operation'), ('C', 'Context record'), ('F', 'Find')], default='A', max_length=1, verbose_name='Model'),
+ preserve_default=False,
+ ),
]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index a6aab9416..e52d210a6 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -4683,9 +4683,18 @@ def author_post_save(sender, **kwargs):
post_save.connect(author_post_save, sender=Author)
+MODELS_FOR_QUALIFICATION = (
+ ("S", _("Archaeological site")),
+ ("O", _("Operation")),
+ ("C", _("Context record")),
+ ("F", _("Find")),
+ ("A", _("All")),
+)
+
class QualifiedBiographicalNoteType(OrderedHierarchicalType):
order = models.IntegerField(_("Order"), default=10)
+ model = models.CharField(_("Model"), max_length=2, choices=MODELS_FOR_QUALIFICATION)
class Meta:
verbose_name = _("Qualification type")