summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2026-06-28 17:01:05 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2026-06-28 22:09:50 +0200
commit46df68944a355b2509596c94b80594d1b0c9736f (patch)
tree863ed5a1f6e479aba8e315d675a44dd04e27137d
parente15f03188cb0be5925f768f26ef077bf78c1783b (diff)
downloadIshtar-46df68944a355b2509596c94b80594d1b0c9736f.tar.bz2
Ishtar-46df68944a355b2509596c94b80594d1b0c9736f.zip
✨ sites - db new field: "other name" ; finds - db new fields: "recommendations" and "current storage conditions"
-rw-r--r--archaeological_finds/admin.py10
-rw-r--r--archaeological_finds/migrations/0159_find_current_storage_conditions_preconisations.py83
-rw-r--r--archaeological_finds/migrations/0160_data_migration.json691
-rw-r--r--archaeological_finds/migrations/0160_data_migration_recommandations_storage_conditions.py26
-rw-r--r--archaeological_finds/models.py4
-rw-r--r--archaeological_finds/models_finds.py79
-rw-r--r--archaeological_operations/migrations/0131_archaeologicalsite_other_name.py23
-rw-r--r--archaeological_operations/models.py1
8 files changed, 915 insertions, 2 deletions
diff --git a/archaeological_finds/admin.py b/archaeological_finds/admin.py
index ffff0adc2..b7d0052bd 100644
--- a/archaeological_finds/admin.py
+++ b/archaeological_finds/admin.py
@@ -273,6 +273,16 @@ class RecommendedTreatmentTypeAdmin(GeneralTypeAdmin):
LIST_DISPLAY = ["label", "txt_idx", "available", "parent", "order", "comment"]
+@admin.register(models.CurrentStorageConditionType, site=admin_site)
+class CurrentStorageConditionTypeAdmin(GeneralTypeAdmin):
+ LIST_DISPLAY = ["label", "txt_idx", "available", "parent", "order", "comment"]
+
+
+@admin.register(models.RecommendationType, site=admin_site)
+class RecommendationTypeAdmin(GeneralTypeAdmin):
+ LIST_DISPLAY = ["label", "txt_idx", "available", "parent", "order", "comment"]
+
+
general_models = [
models.AlterationCauseType, models.AlterationType, models.BatchType,
models.CollectionEntryModeType, models.IconographicPatternType, models.IntegrityType,
diff --git a/archaeological_finds/migrations/0159_find_current_storage_conditions_preconisations.py b/archaeological_finds/migrations/0159_find_current_storage_conditions_preconisations.py
new file mode 100644
index 000000000..44488d802
--- /dev/null
+++ b/archaeological_finds/migrations/0159_find_current_storage_conditions_preconisations.py
@@ -0,0 +1,83 @@
+# Generated by Django 4.2.21 on 2026-06-28 17:40
+
+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 = [
+ ('archaeological_finds', '0158_statementcondition_add_fields'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='find',
+ name='cached_current_storage_conditions',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached current storage conditions'),
+ ),
+ migrations.AddField(
+ model_name='find',
+ name='cached_recommendations',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached recommendations label'),
+ ),
+ migrations.AddField(
+ model_name='historicalfind',
+ name='cached_current_storage_conditions',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached current storage conditions'),
+ ),
+ migrations.AddField(
+ model_name='historicalfind',
+ name='cached_recommendations',
+ field=models.TextField(blank=True, default='', help_text='Generated automatically - do not edit', verbose_name='Cached recommendations label'),
+ ),
+ migrations.CreateModel(
+ name='RecommendationType',
+ 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_finds.recommendationtype', verbose_name='Parent')),
+ ],
+ options={
+ 'verbose_name': 'Recommendation type',
+ 'verbose_name_plural': 'Recommendation types',
+ 'ordering': ('parent__order', 'parent__label', 'order', 'label'),
+ },
+ bases=(ishtar_common.models_common.Cached, models.Model),
+ ),
+ migrations.CreateModel(
+ name='CurrentStorageConditionType',
+ 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_finds.currentstorageconditiontype', verbose_name='Parent')),
+ ],
+ options={
+ 'verbose_name': 'Current storage condition type',
+ 'verbose_name_plural': 'Current storage condition types',
+ 'ordering': ('parent__order', 'parent__label', 'order', 'label'),
+ },
+ bases=(ishtar_common.models_common.Cached, models.Model),
+ ),
+ migrations.AddField(
+ model_name='find',
+ name='current_storage_conditions',
+ field=models.ManyToManyField(blank=True, related_name='finds', to='archaeological_finds.currentstorageconditiontype', verbose_name='Current storage conditions'),
+ ),
+ migrations.AddField(
+ model_name='find',
+ name='recommendations',
+ field=models.ManyToManyField(blank=True, related_name='finds', to='archaeological_finds.recommendationtype', verbose_name='Recommendations'),
+ ),
+ ]
diff --git a/archaeological_finds/migrations/0160_data_migration.json b/archaeological_finds/migrations/0160_data_migration.json
new file mode 100644
index 000000000..cc7aa383f
--- /dev/null
+++ b/archaeological_finds/migrations/0160_data_migration.json
@@ -0,0 +1,691 @@
+[
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "En vitrine",
+ "txt_idx": "en-vitrine",
+ "comment": "",
+ "available": true,
+ "order": 100,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "En r\u00e9serve",
+ "txt_idx": "en-reserve",
+ "comment": "",
+ "available": true,
+ "order": 200,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "En ext\u00e9rieur",
+ "txt_idx": "en-exterieur",
+ "comment": "",
+ "available": true,
+ "order": 300,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Hygrom\u00e9trie",
+ "txt_idx": "hygrometrie",
+ "comment": "",
+ "available": true,
+ "order": 400,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Soclage",
+ "txt_idx": "soclage",
+ "comment": "",
+ "available": true,
+ "order": 500,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "En vitrine climatique",
+ "txt_idx": "en-vitrine-climatique",
+ "comment": "",
+ "available": true,
+ "order": 110,
+ "parent": [
+ "en-vitrine"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "En vitrine herm\u00e9tique",
+ "txt_idx": "en-vitrine-hermetique",
+ "comment": "",
+ "available": true,
+ "order": 120,
+ "parent": [
+ "en-vitrine"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "En vitrine non herm\u00e9tique",
+ "txt_idx": "en-vitrine-non-hermetique",
+ "comment": "",
+ "available": true,
+ "order": 130,
+ "parent": [
+ "en-vitrine"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Contenant herm\u00e9tique",
+ "txt_idx": "contenant-hermetique",
+ "comment": "",
+ "available": true,
+ "order": 210,
+ "parent": [
+ "en-reserve"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Contenant non herm\u00e9tique",
+ "txt_idx": "contenant-non-hermetique",
+ "comment": "",
+ "available": true,
+ "order": 220,
+ "parent": [
+ "en-reserve"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Avec agent dess\u00e9chant",
+ "txt_idx": "avec-agent-dessechant",
+ "comment": "",
+ "available": true,
+ "order": 230,
+ "parent": [
+ "en-reserve"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Contr\u00f4le de l'hygrom\u00e9trie",
+ "txt_idx": "controle-de-lhygrometrie",
+ "comment": "",
+ "available": true,
+ "order": 410,
+ "parent": [
+ "hygrometrie"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Pas de contr\u00f4le de l'hygrom\u00e9trie",
+ "txt_idx": "pas-de-controle-de-lhygrometrie",
+ "comment": "",
+ "available": true,
+ "order": 420,
+ "parent": [
+ "hygrometrie"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Soclage adapt\u00e9",
+ "txt_idx": "soclage-adapte",
+ "comment": "",
+ "available": true,
+ "order": 510,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.currentstorageconditiontype",
+ "fields": {
+ "label": "Soclage inadapt\u00e9",
+ "txt_idx": "soclage-inadapte",
+ "comment": "",
+ "available": true,
+ "order": 520,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Conditionnement",
+ "txt_idx": "conditionnement",
+ "comment": "",
+ "available": true,
+ "order": 100,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Manipulations",
+ "txt_idx": "manipulations",
+ "comment": "",
+ "available": true,
+ "order": 200,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pr\u00e9sentation",
+ "txt_idx": "presentation",
+ "comment": "",
+ "available": true,
+ "order": 300,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Soclage",
+ "txt_idx": "soclage",
+ "comment": "",
+ "available": true,
+ "order": 400,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Environnement",
+ "txt_idx": "environnement",
+ "comment": "",
+ "available": true,
+ "order": 500,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Lumi\u00e8re",
+ "txt_idx": "lumiere",
+ "comment": "",
+ "available": true,
+ "order": 600,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Hygrom\u00e9trie",
+ "txt_idx": "hygrometrie",
+ "comment": "",
+ "available": true,
+ "order": 700,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Temp\u00e9rature",
+ "txt_idx": "temperature",
+ "comment": "",
+ "available": true,
+ "order": 800,
+ "parent": null
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Caler \u00e0 l'aide de mousses de type Plastazote (PE)",
+ "txt_idx": "caler-a-laide-de-mousses",
+ "comment": "",
+ "available": true,
+ "order": 110,
+ "parent": [
+ "conditionnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Emballer dans du papier de soie",
+ "txt_idx": "emballer-dans-du-papier-de-soie",
+ "comment": "",
+ "available": true,
+ "order": 120,
+ "parent": [
+ "conditionnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Transporter dans une caisse \u00e9crin",
+ "txt_idx": "transporter-dans-une-caisse-ecrin",
+ "comment": "",
+ "available": true,
+ "order": 130,
+ "parent": [
+ "conditionnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Transporter dans une caisse \u00e9crin avec pieds anti-vibration",
+ "txt_idx": "transporter-dans-une-caisse-ecrin-avec-pieds-anti-vibration",
+ "comment": "",
+ "available": true,
+ "order": 140,
+ "parent": [
+ "conditionnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Transporter dans une caisse rigide de type norme Europe",
+ "txt_idx": "transporter-dans-une-caisse-rigide-de-type-norme-europe",
+ "comment": "",
+ "available": true,
+ "order": 150,
+ "parent": [
+ "conditionnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Manipuler avec des gants en nitrile ou des mains propres",
+ "txt_idx": "manipuler-avec-des-gants",
+ "comment": "",
+ "available": true,
+ "order": 210,
+ "parent": [
+ "manipulations"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Manipuler avec un support pour \u00e9viter de faire c\u00e9der le collage",
+ "txt_idx": "manipuler-avec-un-support",
+ "comment": "",
+ "available": true,
+ "order": 220,
+ "parent": [
+ "manipulations"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Risque de rupture ou d\u2019alt\u00e9ration de l\u2019objet",
+ "txt_idx": "risque-de-rupture-ou-dalteration-de-lobjet",
+ "comment": "",
+ "available": true,
+ "order": 230,
+ "parent": [
+ "manipulations"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Limiter l'exposition aux vibrations",
+ "txt_idx": "limiter-exposition-aux-vibrations",
+ "comment": "",
+ "available": true,
+ "order": 310,
+ "parent": [
+ "presentation"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Ne pas poser sur un support abrasif",
+ "txt_idx": "pas-de-support-abrasif",
+ "comment": "",
+ "available": true,
+ "order": 320,
+ "parent": [
+ "presentation"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Placer un intercalaire entre le fond de vitrine et l'objet (M\u00e9linex, plastazote...)",
+ "txt_idx": "intercalaire",
+ "comment": "",
+ "available": true,
+ "order": 330,
+ "parent": [
+ "presentation"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pr\u00e9sence d'un tiroir pour agent dessicant",
+ "txt_idx": "agent-dessicant",
+ "comment": "",
+ "available": true,
+ "order": 340,
+ "parent": [
+ "presentation"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Vitrine herm\u00e9tique avec contr\u00f4le de l'hygrom\u00e9trie",
+ "txt_idx": "vitrine-hermetique-hygrometrie",
+ "comment": "",
+ "available": true,
+ "order": 350,
+ "parent": [
+ "presentation"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Attention, collages fragiles",
+ "txt_idx": "attention-collages-fragiles",
+ "comment": "",
+ "available": true,
+ "order": 410,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "La r\u00e9alisation du soclage doit \u00eatre soumise \u00e0 l'approbation pr\u00e9alable des propri\u00e9taires de l'objet",
+ "txt_idx": "approbation-soclage",
+ "comment": "",
+ "available": true,
+ "order": 420,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pr\u00e9senter \u00e0 plat ou pr\u00e9voir un soclage adapt\u00e9 \u00e0 l'objet de mani\u00e8re \u00e0 assurer son maintien",
+ "txt_idx": "presentation-a-plat",
+ "comment": "",
+ "available": true,
+ "order": 430,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pr\u00e9voir un soclage adapt\u00e9 \u00e0 l'objet",
+ "txt_idx": "soclage-adapte",
+ "comment": "",
+ "available": true,
+ "order": 440,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "S'il est ind\u00e9pendant des structures mus\u00e9ographiques, le soclage sera restitu\u00e9 avec l'objet",
+ "txt_idx": "restituer-soclage",
+ "comment": "",
+ "available": true,
+ "order": 450,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Utiliser le soclage transmis avec l\u2019objet",
+ "txt_idx": "utiliser-soclage-transmis",
+ "comment": "",
+ "available": true,
+ "order": 460,
+ "parent": [
+ "soclage"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Hygrom\u00e9trie et temp\u00e9rature stables",
+ "txt_idx": "hygrometrie-et-temperature-stables",
+ "comment": "",
+ "available": true,
+ "order": 510,
+ "parent": [
+ "environnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pas de lumi\u00e8re directe sur l'objet",
+ "txt_idx": "pas-de-lumiere-directe",
+ "comment": "",
+ "available": true,
+ "order": 520,
+ "parent": [
+ "environnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pas de lumi\u00e8re qui chauffe dans la vitrine",
+ "txt_idx": "pas-de-lumiere-qui-chauffe",
+ "comment": "",
+ "available": true,
+ "order": 530,
+ "parent": [
+ "environnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pr\u00e9sence dans la vitrine d\u2019un stabilisateur d\u2019humidit\u00e9 \u00e0 l'hygrom\u00e9trie conseill\u00e9e",
+ "txt_idx": "presence-stabilisateur-humidite",
+ "comment": "",
+ "available": true,
+ "order": 540,
+ "parent": [
+ "environnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Pr\u00e9sence dans la vitrine d\u2019un absorbeur de polluants",
+ "txt_idx": "presence-absorbeur-polluants",
+ "comment": "",
+ "available": true,
+ "order": 550,
+ "parent": [
+ "environnement"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "< 150 Lux",
+ "txt_idx": "inferieur-150-lux",
+ "comment": "",
+ "available": true,
+ "order": 610,
+ "parent": [
+ "lumiere"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "150 Lux",
+ "txt_idx": "150-lux",
+ "comment": "",
+ "available": true,
+ "order": 620,
+ "parent": [
+ "lumiere"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "< 30%",
+ "txt_idx": "inferieur-30pc",
+ "comment": "",
+ "available": true,
+ "order": 710,
+ "parent": [
+ "hygrometrie"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "40-45% +/- 10%",
+ "txt_idx": "40-45pc",
+ "comment": "",
+ "available": true,
+ "order": 720,
+ "parent": [
+ "hygrometrie"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "50% +/- 10%",
+ "txt_idx": "50pc",
+ "comment": "",
+ "available": true,
+ "order": 730,
+ "parent": [
+ "hygrometrie"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "21 +/- 2\u00b0C",
+ "txt_idx": "21-2c",
+ "comment": "",
+ "available": true,
+ "order": 810,
+ "parent": [
+ "temperature"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Risque de rupture des collages",
+ "txt_idx": "risque-de-rupture-des-collages",
+ "comment": "",
+ "available": true,
+ "order": 240,
+ "parent": [
+ "risque-de-rupture-ou-dalteration-de-lobjet"
+ ]
+ }
+ },
+ {
+ "model": "archaeological_finds.recommendationtype",
+ "fields": {
+ "label": "Risque d'effritement des surfaces",
+ "txt_idx": "risque-deffritement-des-surfaces",
+ "comment": "",
+ "available": true,
+ "order": 250,
+ "parent": [
+ "risque-de-rupture-ou-dalteration-de-lobjet"
+ ]
+ }
+ }
+]
diff --git a/archaeological_finds/migrations/0160_data_migration_recommandations_storage_conditions.py b/archaeological_finds/migrations/0160_data_migration_recommandations_storage_conditions.py
new file mode 100644
index 000000000..dab7320b6
--- /dev/null
+++ b/archaeological_finds/migrations/0160_data_migration_recommandations_storage_conditions.py
@@ -0,0 +1,26 @@
+# Generated by Django 2.2.24 on 2024-02-10 12:07
+
+import os
+
+from django.db import migrations
+from django.core.management import call_command
+
+
+def load_data(apps, __):
+ RecommendationType = apps.get_model("archaeological_finds",
+ "RecommendationType")
+ if not RecommendationType.objects.count():
+ json_path = os.sep.join(os.path.abspath(__file__).split(os.sep)[:-1] + [
+ "0160_data_migration.json"])
+ call_command("loaddata", json_path)
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_finds', '0159_find_current_storage_conditions_preconisations'),
+ ]
+
+ operations = [
+ migrations.RunPython(load_data)
+ ]
diff --git a/archaeological_finds/models.py b/archaeological_finds/models.py
index 12e6a05cb..3c48b9dee 100644
--- a/archaeological_finds/models.py
+++ b/archaeological_finds/models.py
@@ -8,6 +8,7 @@ from archaeological_finds.models_finds import (
CollectionEntryModeType,
CommunicabilityType,
ConservatoryState,
+ CurrentStorageConditionType,
DiscoveryMethod,
FBulkView,
Find,
@@ -34,6 +35,7 @@ from archaeological_finds.models_finds import (
OwnershipStatus,
OwnerType,
Property,
+ RecommendationType,
RecommendedTreatmentType,
RemarkabilityType,
TechnicalAreaType,
@@ -72,6 +74,7 @@ __all__ = [
"CollectionEntryModeType",
"CommunicabilityType",
"ConservatoryState",
+ "CurrentStorageConditionType",
"DiscoveryMethod",
"Exhibition",
"ExhibitionType",
@@ -105,6 +108,7 @@ __all__ = [
"OwnershipStatus",
"OwnerType",
"Property",
+ "RecommendationType",
"RemarkabilityType",
"RecommendedTreatmentType",
"StatementCondition",
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index 7e789a578..b1cd40539 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -528,6 +528,40 @@ post_save.connect(post_save_cache, sender=RecommendedTreatmentType)
post_delete.connect(post_save_cache, sender=RecommendedTreatmentType)
+class RecommendationType(OrderedHierarchicalType):
+ class Meta:
+ verbose_name = _("Recommendation type")
+ verbose_name_plural = _("Recommendation types")
+ ordering = (
+ "parent__order",
+ "parent__label",
+ "order",
+ "label",
+ )
+ ADMIN_SECTION = _("Finds")
+
+
+post_save.connect(post_save_cache, sender=RecommendationType)
+post_delete.connect(post_save_cache, sender=RecommendationType)
+
+
+class CurrentStorageConditionType(OrderedHierarchicalType):
+ class Meta:
+ verbose_name = _("Current storage condition type")
+ verbose_name_plural = _("Current storage condition types")
+ ordering = (
+ "parent__order",
+ "parent__label",
+ "order",
+ "label",
+ )
+ ADMIN_SECTION = _("Finds")
+
+
+post_save.connect(post_save_cache, sender=CurrentStorageConditionType)
+post_delete.connect(post_save_cache, sender=CurrentStorageConditionType)
+
+
class InventoryMarkingPresence(OrderedType):
class Meta:
verbose_name = _("Presence of inventory marking type")
@@ -2245,6 +2279,8 @@ class Find(
"recommended_treatments",
"alterations",
"alteration_causes",
+ "recommendations",
+ "current_storage_conditions",
]
GET_VALUES_EXTRA = ValueGetter.GET_VALUES_EXTRA + ["complete_id",
"context_record_label"]
@@ -2267,6 +2303,8 @@ class Find(
"remarkabilities",
"technical_areas",
"technical_processes",
+ "recommendations",
+ "current_storage_conditions",
]
CACHED_LABELS = [
"cache_complete_museum_id",
@@ -2274,6 +2312,8 @@ class Find(
"cached_periods",
"cached_object_types",
"cached_materials",
+ "cached_recommendations",
+ "cached_current_storage_conditions",
]
SERIALIZE_CALL = {
"base_finds_list": "base_finds_list",
@@ -2646,6 +2686,18 @@ class Find(
)
insurance_value = models.FloatField(_("Insurance value"), blank=True, null=True)
appraisal_date = models.DateField(_("Appraisal date"), blank=True, null=True)
+ recommendations = models.ManyToManyField(
+ RecommendationType,
+ verbose_name=_("Recommendations"),
+ blank=True,
+ related_name="finds",
+ )
+ current_storage_conditions = models.ManyToManyField(
+ CurrentStorageConditionType,
+ verbose_name=_("Current storage conditions"),
+ blank=True,
+ related_name="finds",
+ )
public_description = models.TextField(
_("Public description"), blank=True, default=""
)
@@ -2686,6 +2738,18 @@ class Find(
default="",
help_text=_("Generated automatically - do not edit"),
)
+ cached_recommendations = models.TextField(
+ _("Cached recommendations label"),
+ blank=True,
+ default="",
+ help_text=_("Generated automatically - do not edit"),
+ )
+ cached_current_storage_conditions = models.TextField(
+ _("Cached current storage conditions"),
+ blank=True,
+ default="",
+ help_text=_("Generated automatically - do not edit"),
+ )
cache_complete_museum_id = models.TextField(
_("Complete museum ID"),
blank=True,
@@ -3628,12 +3692,23 @@ class Find(
def _generate_cached_periods(self):
return " & ".join([period.label for period in self.periods.all()])
+
+ def _generate_m2m_label(self, attr):
+ return " & ".join(
+ [str(item) for item in getattr(self, attr).all()]
+ )
def _generate_cached_object_types(self):
- return " & ".join([str(obj) for obj in self.object_types.all()])
+ return self._generate_m2m_label("object_types")
def _generate_cached_materials(self):
- return " & ".join([str(mat) for mat in self.material_types.all()])
+ return self._generate_m2m_label("material_types")
+
+ def _generate_cached_recommendations(self):
+ return self._generate_m2m_label("recommendations")
+
+ def _generate_cached_current_storage_conditions(self):
+ return self._generate_m2m_label("current_storage_conditions")
def get_localisation(self, place, is_ref=False):
"""
diff --git a/archaeological_operations/migrations/0131_archaeologicalsite_other_name.py b/archaeological_operations/migrations/0131_archaeologicalsite_other_name.py
new file mode 100644
index 000000000..8dc74646e
--- /dev/null
+++ b/archaeological_operations/migrations/0131_archaeologicalsite_other_name.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.2.21 on 2026-06-28 17:40
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_operations', '0130_archaeologicalsite_set_not_null'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='other_name',
+ field=models.TextField(blank=True, default='', verbose_name='Other name'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='other_name',
+ field=models.TextField(blank=True, default='', verbose_name='Other name'),
+ ),
+ ]
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index 1c6ab4507..eeccad102 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -718,6 +718,7 @@ class ArchaeologicalSite(
reference = models.CharField(_("Reference"), max_length=200, unique=True)
other_reference = models.TextField(_("Other reference"), blank=True, default="")
name = models.CharField(_("Name"), max_length=200, blank=True, default="")
+ other_name = models.TextField(_("Other name"), blank=True, default="")
types = models.ManyToManyField("SiteType", verbose_name=_("Types"), blank=True)
periods = models.ManyToManyField(Period, verbose_name=_("Periods"), blank=True)
remains = models.ManyToManyField(