diff --git a/.idea/hellforge.iml b/.idea/hellforge.iml
new file mode 100644
index 0000000..b60d2ff
--- /dev/null
+++ b/.idea/hellforge.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..eece9a8
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..32438c3
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..8136602
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1761336038698
+
+
+ 1761336038698
+
+
+
+
\ No newline at end of file
diff --git a/main/migrations/0174_colours.py b/main/migrations/0174_colours.py
new file mode 100644
index 0000000..b1b5a85
--- /dev/null
+++ b/main/migrations/0174_colours.py
@@ -0,0 +1,21 @@
+# Generated by Django 5.1.3 on 2025-09-19 19:38
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0173_project_parameters'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Colours',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('colour_name', models.CharField(max_length=64)),
+ ('colour_munsell', models.CharField(max_length=32)),
+ ],
+ ),
+ ]
diff --git a/main/migrations/0175_colourmunsell_colourname_delete_colours_and_more.py b/main/migrations/0175_colourmunsell_colourname_delete_colours_and_more.py
new file mode 100644
index 0000000..212ff2d
--- /dev/null
+++ b/main/migrations/0175_colourmunsell_colourname_delete_colours_and_more.py
@@ -0,0 +1,37 @@
+# Generated by Django 5.1.3 on 2025-09-23 19:39
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0174_colours'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ColourMunsell',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('colour_munsell', models.CharField(max_length=32)),
+ ('is_default', models.BooleanField(default=False)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='ColourName',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('name', models.CharField(max_length=64)),
+ ('is_default', models.BooleanField(default=False)),
+ ],
+ ),
+ migrations.DeleteModel(
+ name='Colours',
+ ),
+ migrations.AddField(
+ model_name='colourmunsell',
+ name='colour_name',
+ field=models.ManyToManyField(related_name='munsell_value', to='main.colourname'),
+ ),
+ ]
diff --git a/main/migrations/0176_remove_layer_colour_hex_alter_layer_colour_and_more.py b/main/migrations/0176_remove_layer_colour_hex_alter_layer_colour_and_more.py
new file mode 100644
index 0000000..1f522b2
--- /dev/null
+++ b/main/migrations/0176_remove_layer_colour_hex_alter_layer_colour_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 5.1.3 on 2025-09-26 20:42
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0175_colourmunsell_colourname_delete_colours_and_more'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='layer',
+ name='colour_hex',
+ ),
+ migrations.AlterField(
+ model_name='layer',
+ name='colour',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='colour', to='main.colourname'),
+ ),
+ migrations.AlterField(
+ model_name='layer',
+ name='colour_munsell',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='munsell', to='main.colourmunsell'),
+ ),
+ ]
diff --git a/main/migrations/0177_alter_layer_colour_alter_layer_colour_munsell.py b/main/migrations/0177_alter_layer_colour_alter_layer_colour_munsell.py
new file mode 100644
index 0000000..2c5ae7a
--- /dev/null
+++ b/main/migrations/0177_alter_layer_colour_alter_layer_colour_munsell.py
@@ -0,0 +1,24 @@
+# Generated by Django 5.1.3 on 2025-09-26 21:13
+
+import django.core.validators
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0176_remove_layer_colour_hex_alter_layer_colour_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='layer',
+ name='colour',
+ field=models.CharField(blank=True, max_length=200, null=True, verbose_name='colour'),
+ ),
+ migrations.AlterField(
+ model_name='layer',
+ name='colour_munsell',
+ field=models.CharField(blank=True, max_length=200, null=True, validators=[django.core.validators.RegexValidator(code='invalid_registration', message='Enter a valid Munsell Number in the format 8.75YR 4.5/3', regex='^[0-9]+(\\.[0-9]+)?[A-Z]+\\s+[1-9](\\.[0-9]+)?/[0-9]+(\\.[0-9]+)?$')], verbose_name='colour_munsell'),
+ ),
+ ]
diff --git a/main/migrations/0178_alter_layer_colour_alter_layer_colour_munsell.py b/main/migrations/0178_alter_layer_colour_alter_layer_colour_munsell.py
new file mode 100644
index 0000000..1270327
--- /dev/null
+++ b/main/migrations/0178_alter_layer_colour_alter_layer_colour_munsell.py
@@ -0,0 +1,24 @@
+# Generated by Django 5.1.3 on 2025-09-27 16:01
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0177_alter_layer_colour_alter_layer_colour_munsell'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='layer',
+ name='colour',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='colour', to='main.colourname'),
+ ),
+ migrations.AlterField(
+ model_name='layer',
+ name='colour_munsell',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='munsell', to='main.colourmunsell'),
+ ),
+ ]
diff --git a/main/migrations/0179_alter_layer_colour_alter_layer_colour_munsell.py b/main/migrations/0179_alter_layer_colour_alter_layer_colour_munsell.py
new file mode 100644
index 0000000..e27a294
--- /dev/null
+++ b/main/migrations/0179_alter_layer_colour_alter_layer_colour_munsell.py
@@ -0,0 +1,24 @@
+# Generated by Django 5.1.3 on 2025-09-29 20:21
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0178_alter_layer_colour_alter_layer_colour_munsell'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='layer',
+ name='colour',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='colour', to='main.colourname'),
+ ),
+ migrations.AlterField(
+ model_name='layer',
+ name='colour_munsell',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='munsell', to='main.colourmunsell'),
+ ),
+ ]
diff --git a/main/migrations/0180_texturecategory_texturekeyword.py b/main/migrations/0180_texturecategory_texturekeyword.py
new file mode 100644
index 0000000..6066ef8
--- /dev/null
+++ b/main/migrations/0180_texturecategory_texturekeyword.py
@@ -0,0 +1,29 @@
+# Generated by Django 5.1.3 on 2025-09-30 20:20
+
+import django.db.models.deletion
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0179_alter_layer_colour_alter_layer_colour_munsell'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='TextureCategory',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('category', models.CharField(max_length=32)),
+ ],
+ ),
+ migrations.CreateModel(
+ name='TextureKeyword',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('texture', models.CharField(max_length=64)),
+ ('texture_category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='texture_category', to='main.texturecategory')),
+ ],
+ ),
+ ]
diff --git a/main/models.py b/main/models.py
index 3880839..5808dce 100644
--- a/main/models.py
+++ b/main/models.py
@@ -1,7 +1,7 @@
import json
from django.db import models
from django.urls import reverse
-from django.db.models import Q
+from django.db.models import Q, CASCADE
from django.core.validators import RegexValidator
from django.contrib.contenttypes.fields import GenericForeignKey # for the description
from django.contrib.contenttypes.models import ContentType # for the description
@@ -1083,6 +1083,21 @@ def get_data(self, **kwargs):
'Silt'
]}
+class ColourName(models.Model):
+ name = models.CharField(max_length=64)
+ is_default = models.BooleanField(default=False)
+
+class ColourMunsell(models.Model):
+ colour_munsell = models.CharField(max_length=32)
+ colour_name = models.ManyToManyField(ColourName, related_name="munsell_value")
+ is_default = models.BooleanField(default=False)
+
+class TextureCategory(models.Model):
+ category = models.CharField(max_length=32)
+
+class TextureKeyword(models.Model):
+ texture = models.CharField(max_length=64)
+ texture_category = models.ForeignKey(TextureCategory, on_delete=models.CASCADE, related_name="texture_category")
class Layer(Dateable):
name = models.CharField("name", max_length=200)
@@ -1130,21 +1145,24 @@ class Layer(Dateable):
null=True,
)
# fields related to geological sediment properties
- colour = models.CharField("colour",max_length=200, blank=True, null=True) # this is the "informal" name
- colour_munsell = models.CharField(
- "colour_munsell",
- max_length=200,
- validators=[
- RegexValidator(
- regex=r'^[0-9]+(\.[0-9]+)?[A-Z]+\s+[1-9](\.[0-9]+)?/[0-9]+(\.[0-9]+)?$',
- message="Enter a valid Munsell Number in the format 8.75YR 4.5/3",
- code="invalid_registration",
- ),
- ],
- blank=True,
- null=True) # The Munsell Color Code
- colour_hex = models.CharField("colour_rgb", max_length=200, blank=True, null=True) # The hex value calculated from Munsell
+ #colour = models.CharField("colour",max_length=200, blank=True, null=True) # this is the "informal" name
+ #colour_munsell = models.CharField(
+ # "colour_munsell",
+ # max_length=200,
+ # validators=[
+ # RegexValidator(
+ # regex=r'^[0-9]+(\.[0-9]+)?[A-Z]+\s+[1-9](\.[0-9]+)?/[0-9]+(\.[0-9]+)?$',
+ # message="Enter a valid Munsell Number in the format 8.75YR 4.5/3",
+ # code="invalid_registration",
+ # ),
+ # ],
+ # blank=True,
+ # null=True) # The Munsell Color Code
+ colour = models.ForeignKey(ColourName, blank=True, null=True, on_delete=models.SET_NULL, related_name="colour")
+ colour_munsell = models.ForeignKey(ColourMunsell, blank=True, null=True, on_delete=models.SET_NULL, related_name="munsell")
+ #colour_hex = models.CharField("colour_rgb", max_length=200, blank=True, null=True) # The hex value calculated from Munsell
texture = models.CharField("texture", max_length=200, blank=True, null=True, choices=texture_choices)
+ texture_keyword = models.ForeignKey(TextureKeyword, blank=True, null=True, on_delete=models.SET_NULL, related_name="texture")
#
## References
@@ -1775,6 +1793,13 @@ def get_data(self, **kwargs):
new_data = {(f"MM_{k}" if k in duplicates else k):v for k,v in data.items() } # preserve column names in data
return new_data
+#
+#
+# Classes for Colour and Texture Databases
+#
+#
+
+
models = {
"site": Site,
diff --git a/main/signals.py b/main/signals.py
index c3d83be..bc67fc6 100644
--- a/main/signals.py
+++ b/main/signals.py
@@ -12,7 +12,9 @@
FaunalResults,
Reference,
SampleBatch,
- Gallery
+ Gallery,
+ ColourName,
+ ColourMunsell
)
from main.tools import dating
import json
@@ -189,6 +191,18 @@ def update_order(sender, instance, **kwargs):
@receiver(pre_save, sender=Layer)
def update_colour(sender, instance, **kwargs):
+ if instance.colour_munsell and not instance.colour:
+ colour_link = instance.colour_munsell.colour_name.filter(is_default=True)
+ if colour_link.exists():
+ instance.colour = colour_link.first()
+ else:
+ instance.colour = instance.colour_munsell.colour_name.first()
+ elif instance.colour and not instance.colour_munsell:
+ munsell_link = instance.colour.munsell_value.filter(is_default=True)
+ if munsell_link.exists():
+ instance.colour_munsell = munsell_link.first()
+ else:
+ instance.colour_munsell = instance.colour.munsell_value.first()
# unset the hex-colour
if instance.colour_munsell == "" or not instance.colour_munsell:
instance.colour_hex = None
diff --git a/main/tools/colours_textures.py b/main/tools/colours_textures.py
new file mode 100644
index 0000000..cb1a899
--- /dev/null
+++ b/main/tools/colours_textures.py
@@ -0,0 +1,92 @@
+#from colour.examples.notation.examples_munsell import munsell_colour
+#from weasyprint.css.computed_values import length
+from unicodedata import category
+
+from main.models import ColourName, ColourMunsell, Layer, Site, TextureCategory, TextureKeyword
+from main.forms import ReferenceForm, LayerColourForm
+import csv
+
+#add input string cleanup before creation!
+def import_colours_from_csv(path):
+ with open(path) as file:
+ reader = csv.reader(file, delimiter="\t")
+ for row in reader:
+ name_new, created = ColourName.objects.get_or_create(
+ name=row[0]
+ )
+ if created:
+ name_new.is_default = False if len(row) < 4 else row[3].strip().lower()=="true"
+ name_new.save()
+ _ ,created_m = ColourMunsell.objects.get_or_create(
+ colour_munsell=row[1],
+ )
+ _.is_default = False if len(row) < 3 else row[2].strip().lower()=="true"
+ _.colour_name.add(name_new)
+ _.save()
+
+def update_layer_colours_new(path):
+ with open(path) as file:
+ reader = csv.reader(file, delimiter="\t")
+ for row in reader:
+ colour_keyword = row[13]
+ if colour_keyword != "":
+ site = Site.objects.filter(name=row[0])
+ if site.exists():
+ layer = Layer.objects.filter(name=row[2], site=site[0])
+ if layer.exists():
+ layer = layer.first()
+ if colour_keyword[0].isdigit(): # is colour keyword a munsell value?
+ new_colour_munsell = ColourMunsell.objects.filter(colour_munsell=colour_keyword)
+ if new_colour_munsell.exists():
+ new_colour_munsell_entry = new_colour_munsell[0]
+ layer.colour_munsell = new_colour_munsell_entry
+ layer.save()
+ else:
+ print("Munsell value " + colour_keyword + " does not exist.")
+ continue
+ else:
+ new_colour_name = ColourName.objects.filter(name=colour_keyword)
+ if new_colour_name.exists():
+ new_colour_name_entry = new_colour_name[0]
+ layer.colour = new_colour_name_entry
+ layer.save()
+ else:
+ print("Colour " + colour_keyword + " does not exist.")
+ continue
+ else:
+ print("Layer " + row[2] + " of site " + row[0] + " does not exist.")
+ continue
+ else:
+ print("Site " + row[0] + " does not exist.")
+ continue
+
+#for initially creating category database entries
+def make_texture_db():
+ categories = ["silty clay",
+ "sandy clay loam",
+ "silty clay loam",
+ "clay loam",
+ "sandy loam",
+ "silt loam",
+ "loam",
+ "silt",
+ "loamy sand",
+ "sand",
+ "clay",
+ "sandy clay"]
+ for entry in categories:
+ new_cat, created = TextureCategory.objects.get_or_create(category=entry)
+ new_cat.save()
+
+#for adding keywords and pairing to categories
+def update_textures(path):
+ with open(path) as file:
+ reader = csv.reader(file, delimiter="\t")
+ for row in reader:
+ print(row)
+ new_keyword, created = TextureKeyword.objects.get_or_create(
+ texture = row[0],
+ texture_category = TextureCategory.objects.get(category=row[1].lower())
+ )
+ if created:
+ new_keyword.save()
\ No newline at end of file