diff --git a/webportal/management/commands/delete_assembly_cells.py b/webportal/management/commands/delete_assembly_cells.py new file mode 100644 index 0000000..ee2b042 --- /dev/null +++ b/webportal/management/commands/delete_assembly_cells.py @@ -0,0 +1,17 @@ +from django.core.management.base import BaseCommand + +from webportal.models import Cell + + +class Command(BaseCommand): + help = """ + Delete all the Assembly cells from the database. + To run: 'python manage.py delete_assembly_cells' + """ + + def handle(self, *args, **kwargs): + num_assemblies = Cell.objects.count() + Cell.objects.all().delete() + self.stdout.write( + self.style.SUCCESS(f"{num_assemblies} assembly-cells deleted successfully.") + ) diff --git a/webportal/management/commands/delete_assembly_layers.py b/webportal/management/commands/delete_assembly_layers.py new file mode 100644 index 0000000..f8432a3 --- /dev/null +++ b/webportal/management/commands/delete_assembly_layers.py @@ -0,0 +1,19 @@ +from django.core.management.base import BaseCommand + +from webportal.models import Layer + + +class Command(BaseCommand): + help = """ + Delete all the Assembly cells from the database. + To run: 'python manage.py delete_assembly_layers' + """ + + def handle(self, *args, **kwargs): + num_assemblies = Layer.objects.count() + Layer.objects.all().delete() + self.stdout.write( + self.style.SUCCESS( + f"{num_assemblies} assembly-layers deleted successfully." + ) + ) diff --git a/webportal/migrations/0010_remove_cell_column_number_remove_cell_container_and_more.py b/webportal/migrations/0010_remove_cell_column_number_remove_cell_container_and_more.py new file mode 100644 index 0000000..83d800f --- /dev/null +++ b/webportal/migrations/0010_remove_cell_column_number_remove_cell_container_and_more.py @@ -0,0 +1,69 @@ +# Generated by Django 5.1.3 on 2024-12-12 17:25 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("webportal", "0009_alter_material_unique_id"), + ] + + operations = [ + migrations.RemoveField( + model_name="cell", + name="column_number", + ), + migrations.RemoveField( + model_name="cell", + name="container", + ), + migrations.RemoveField( + model_name="cell", + name="row_number", + ), + migrations.AddField( + model_name="assembly", + name="layer_id_order", + field=models.JSONField(default=list), + ), + migrations.AlterField( + model_name="material", + name="unique_id", + field=models.CharField(default="90dd06", max_length=6, unique=True), + ), + migrations.CreateModel( + name="Layer", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("thickness", models.FloatField()), + ( + "assembly", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="layers", + to="webportal.assembly", + ), + ), + ], + ), + migrations.AddField( + model_name="cell", + name="layer", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="cells", + to="webportal.layer", + ), + ), + ] diff --git a/webportal/migrations/0011_alter_material_unique_id.py b/webportal/migrations/0011_alter_material_unique_id.py new file mode 100644 index 0000000..e45cc09 --- /dev/null +++ b/webportal/migrations/0011_alter_material_unique_id.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.3 on 2024-12-12 17:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("webportal", "0010_remove_cell_column_number_remove_cell_container_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="material", + name="unique_id", + field=models.CharField(default="2d95fc", max_length=6, unique=True), + ), + ] diff --git a/webportal/migrations/0012_alter_material_unique_id.py b/webportal/migrations/0012_alter_material_unique_id.py new file mode 100644 index 0000000..f656846 --- /dev/null +++ b/webportal/migrations/0012_alter_material_unique_id.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.3 on 2024-12-12 18:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("webportal", "0011_alter_material_unique_id"), + ] + + operations = [ + migrations.AlterField( + model_name="material", + name="unique_id", + field=models.CharField(default="7f013d", max_length=6, unique=True), + ), + ] diff --git a/webportal/models.py b/webportal/models.py index 83bc735..c12b6b0 100644 --- a/webportal/models.py +++ b/webportal/models.py @@ -3,6 +3,8 @@ from django.contrib.auth.models import AbstractUser from django.db import models +from typing import Any + # --------------------------------------------------------------------------------------- # -- Users @@ -114,21 +116,62 @@ class Assembly(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, null=False, blank=False) name = models.CharField(max_length=100, default="assembly") created_at = models.DateTimeField(auto_now_add=True) + layer_id_order = models.JSONField(default=list) + + def get_ordered_layers(self) -> list["Layer"]: + """Return layers ordered according to the layer_id_order field.""" + # Sort layers by the order in layer_order + layers = {layer.id: layer for layer in self.layers.all()} + return [ + layers[layer_id] for layer_id in self.layer_id_order if layer_id in layers + ] + + def delete_layer(self, layer_pk: int) -> None: + """Delete a layer from the assembly.""" + if layer_pk in self.layer_id_order: + self.layer_id_order.remove(layer_pk) + self.save() + + def save(self, *args, **kwargs) -> None: + super().save(*args, **kwargs) + layers = Layer.objects.filter(assembly=self) + if not layers.exists(): + new_layer = Layer.objects.create(assembly=self, thickness=1.0) + self.layer_id_order.append(new_layer.id) - def save(self, *args, **kwargs): + @property + def layers(self) -> models.QuerySet["Layer"]: + return self.layer_set.all() # type: ignore + + def __str__(self) -> str: + return self.name + + +class Layer(models.Model): + assembly = models.ForeignKey( + Assembly, on_delete=models.CASCADE, related_name="layers" + ) + thickness = models.FloatField() + + def save(self, *args, **kwargs) -> None: super().save(*args, **kwargs) - cells = Cell.objects.filter(container=self) + cells = Cell.objects.filter(layer=self) if not cells.exists(): - Cell.objects.create(container=self, column_number=1, row_number=1) + Cell.objects.create(layer=self) + + @property + def id(self) -> int: + return self.id + + def __str__(self) -> str: + return f"{self.thickness} mm" class Cell(models.Model): - container = models.ForeignKey( - Assembly, on_delete=models.CASCADE, related_name="cells" + layer = models.ForeignKey( + Layer, on_delete=models.CASCADE, null=True, related_name="cells" ) - column_number = models.IntegerField() - row_number = models.IntegerField() value = models.TextField(blank=True, null=True) def __str__(self): - return f"{self.container.name} Cell: [{self.row_number}:{self.column_number}]" + return f"[layer-{self.layer}]: {self.value}" diff --git a/webportal/templates/webportal/partials/assemblies/assembly-detail.html b/webportal/templates/webportal/partials/assemblies/assembly-detail.html deleted file mode 100644 index 3aebab9..0000000 --- a/webportal/templates/webportal/partials/assemblies/assembly-detail.html +++ /dev/null @@ -1,26 +0,0 @@ -