Image handling refined (filenames, mobile rendering)
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
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
This commit is contained in:
@@ -18,7 +18,7 @@ spec:
|
||||
fsGroupChangePolicy: "OnRootMismatch"
|
||||
initContainers:
|
||||
- name: loader
|
||||
image: git.baumann.gr/adebaumann/labhelper-data-loader:0.010
|
||||
image: git.baumann.gr/adebaumann/labhelper-data-loader:0.011
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
command: [ "sh","-c","if [ ! -f /data/db.sqlite3 ] || [ ! -s /data/db.sqlite3 ]; then cp preload/preload.sqlite3 /data/db.sqlite3 && echo 'Database copied from preload'; else echo 'Existing database preserved'; fi" ]
|
||||
@@ -27,7 +27,7 @@ spec:
|
||||
mountPath: /data
|
||||
containers:
|
||||
- name: web
|
||||
image: git.baumann.gr/adebaumann/labhelper:0.032
|
||||
image: git.baumann.gr/adebaumann/labhelper:0.033
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8000
|
||||
|
||||
19
boxes/migrations/0004_alter_thing_picture.py
Normal file
19
boxes/migrations/0004_alter_thing_picture.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.9 on 2025-12-29 18:26
|
||||
|
||||
import boxes.models
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('boxes', '0003_convert_thingtype_to_mptt'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='thing',
|
||||
name='picture',
|
||||
field=models.ImageField(blank=True, upload_to=boxes.models.thing_picture_upload_path),
|
||||
),
|
||||
]
|
||||
@@ -1,7 +1,19 @@
|
||||
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."""
|
||||
|
||||
@@ -72,10 +84,29 @@ class Thing(models.Model):
|
||||
related_name='things'
|
||||
)
|
||||
description = models.TextField(blank=True)
|
||||
picture = models.ImageField(upload_to='things/', 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
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
<div class="thing-image" style="flex-shrink: 0;">
|
||||
{% if thing.picture %}
|
||||
{% thumbnail thing.picture "400x400" crop="center" as thumb %}
|
||||
<img src="{{ thumb.url }}" alt="{{ thing.name }}" style="width: 400px; height: 400px; object-fit: cover; border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.15);">
|
||||
<img src="{{ thumb.url }}" alt="{{ thing.name }}" style="max-width: 100%; width: 400px; height: 400px; object-fit: cover; border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.15);">
|
||||
{% endthumbnail %}
|
||||
{% else %}
|
||||
<div style="width: 400px; height: 400px; background: linear-gradient(135deg, #e0e0e0 0%, #f0f0f0 100%); display: flex; align-items: center; justify-content: center; color: #999; border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.15);">
|
||||
<div style="max-width: 100%; width: 400px; height: 400px; background: linear-gradient(135deg, #e0e0e0 0%, #f0f0f0 100%); display: flex; align-items: center; justify-content: center; color: #999; border-radius: 12px; box-shadow: 0 8px 24px rgba(0,0,0,0.15);">
|
||||
<div style="text-align: center;">
|
||||
<i class="fas fa-image" style="font-size: 64px; margin-bottom: 15px; display: block;"></i>
|
||||
No image
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user