Files
labhelper/boxes/models.py
Adrian A. Baumann 1d1c80a267
All checks were successful
Build containers when image tags change / build-if-image-changed (., web, containers, main container, git.baumann.gr/adebaumann/labhelper) (push) Successful in 1m9s
Build containers when image tags change / build-if-image-changed (data-loader, loader, initContainers, init-container, git.baumann.gr/adebaumann/labhelper-data-loader) (push) Successful in 56s
Image handling refined (filenames, mobile rendering)
2025-12-29 19:52:22 +01:00

113 lines
3.2 KiB
Python

import os
from django.db import models
from django.utils.text import slugify
from mptt.models import MPTTModel, TreeForeignKey
def thing_picture_upload_path(instance, filename):
"""Generate a custom path for thing pictures in format: <id>-<name>.<extension>"""
extension = os.path.splitext(filename)[1]
safe_name = slugify(instance.name)
if instance.pk:
return f'things/{instance.pk}-{safe_name}{extension}'
else:
return f'things/temp-{safe_name}{extension}'
class BoxType(models.Model):
"""A type of storage box with specific dimensions."""
name = models.CharField(max_length=255)
width = models.PositiveIntegerField(help_text='Width in millimeters')
height = models.PositiveIntegerField(help_text='Height in millimeters')
length = models.PositiveIntegerField(help_text='Length in millimeters')
class Meta:
ordering = ['name']
def __str__(self):
return self.name
class Box(models.Model):
"""A storage box in the lab."""
id = models.CharField(
max_length=10,
primary_key=True,
help_text='Alphanumeric identifier (max 10 characters)'
)
box_type = models.ForeignKey(
BoxType,
on_delete=models.PROTECT,
related_name='boxes'
)
class Meta:
verbose_name_plural = 'boxes'
def __str__(self):
return self.id
class ThingType(MPTTModel):
"""A hierarchical type/category for things stored in boxes."""
name = models.CharField(max_length=255)
parent = TreeForeignKey(
'self',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='children'
)
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
return self.name
class Thing(models.Model):
"""An item stored in a box."""
name = models.CharField(max_length=255)
thing_type = models.ForeignKey(
ThingType,
on_delete=models.PROTECT,
related_name='things'
)
box = models.ForeignKey(
Box,
on_delete=models.PROTECT,
related_name='things'
)
description = models.TextField(blank=True)
picture = models.ImageField(upload_to=thing_picture_upload_path, blank=True)
class Meta:
ordering = ['name']
def save(self, *args, **kwargs):
"""Override save to rename picture file after instance gets a pk."""
if self.picture and not self.pk:
picture = self.picture
super().save(*args, **kwargs)
new_path = thing_picture_upload_path(self, picture.name)
if picture.name != new_path:
try:
old_path = self.picture.path
if os.path.exists(old_path):
new_full_path = os.path.join(os.path.dirname(old_path), os.path.basename(new_path))
os.rename(old_path, new_full_path)
self.picture.name = new_path
super().save(update_fields=['picture'])
except (AttributeError, FileNotFoundError):
pass
else:
super().save(*args, **kwargs)
def __str__(self):
return self.name