ref: use thumbnail image instead of size limit

This commit is contained in:
relikd
2024-07-28 22:41:04 +02:00
parent d009d3ab3a
commit b98b882665
4 changed files with 24 additions and 36 deletions

View File

@@ -69,7 +69,7 @@ class Migration(migrations.Migration):
('sort', models.IntegerField(default=0, verbose_name='Sortierung')), ('sort', models.IntegerField(default=0, verbose_name='Sortierung')),
('isExtended', models.BooleanField(verbose_name='Bis 1.1.2025 verstecken')), ('isExtended', models.BooleanField(verbose_name='Bis 1.1.2025 verstecken')),
('title', models.CharField(max_length=100, verbose_name='Titel')), ('title', models.CharField(max_length=100, verbose_name='Titel')),
('image', common.form.img_with_preview.FileWithImagePreview(blank=True, null=True, upload_to=app.models.place.overwrite_img_upload, verbose_name='Bild')), ('image', common.form.img_with_preview.ThumbnailImageField(blank=True, null=True, upload_to=app.models.place.overwrite_img_upload, verbose_name='Bild')),
('audio', common.form.audio_file.AudioFileField(blank=True, null=True, upload_to=app.models.place.overwrite_audio_upload, verbose_name='Audio')), ('audio', common.form.audio_file.AudioFileField(blank=True, null=True, upload_to=app.models.place.overwrite_audio_upload, verbose_name='Audio')),
('location', map_location.fields.LocationField(blank=True, null=True, verbose_name='Position')), ('location', map_location.fields.LocationField(blank=True, null=True, verbose_name='Position')),
('description', tinymce.models.HTMLField(verbose_name='Beschreibung')), ('description', tinymce.models.HTMLField(verbose_name='Beschreibung')),

View File

@@ -13,7 +13,7 @@ from map_location.fields import LocationField
from app.models.category import Category from app.models.category import Category
from common.form.audio_file import AudioFileField from common.form.audio_file import AudioFileField
from common.form.img_with_preview import FileWithImagePreview from common.form.img_with_preview import ThumbnailImageField
def overwrite_img_upload(instance: 'Place', filename: str): def overwrite_img_upload(instance: 'Place', filename: str):
@@ -38,8 +38,8 @@ class Place(models.Model):
sort = models.IntegerField('Sortierung', default=0) sort = models.IntegerField('Sortierung', default=0)
isExtended = models.BooleanField('Bis 1.1.2025 verstecken') isExtended = models.BooleanField('Bis 1.1.2025 verstecken')
title = models.CharField('Titel', max_length=100) title = models.CharField('Titel', max_length=100)
image = FileWithImagePreview('Bild', blank=True, null=True, image = ThumbnailImageField('Bild', blank=True, null=True,
upload_to=overwrite_img_upload) upload_to=overwrite_img_upload) # type: ignore
audio = AudioFileField('Audio', blank=True, null=True, audio = AudioFileField('Audio', blank=True, null=True,
upload_to=overwrite_audio_upload) upload_to=overwrite_audio_upload)
location = LocationField('Position', blank=True, null=True, options={ location = LocationField('Position', blank=True, null=True, options={

View File

@@ -1,13 +1,20 @@
from django import forms
from django.conf import settings from django.conf import settings
from django.contrib.admin.widgets import AdminFileWidget from django.core.files.uploadedfile import UploadedFile
from django.core.validators import FileExtensionValidator
from django.db import models from django.db import models
from django.forms import FileInput, widgets from django.forms import widgets
from common.validators import MaxFilesizeValidator, readableToInt from PIL import Image, ImageOps
MAX_UPLOAD_SIZE = '312 KB'
def makeThumnail(data: UploadedFile, size: 'tuple[int, int]'):
with Image.open(data) as img:
ImageOps.exif_transpose(img, in_place=True)
img.thumbnail(size)
if img.mode != 'RGB':
img = img.convert('RGB')
data.seek(0)
data.truncate()
img.save(data, 'jpeg')
class ImageFileWidget(widgets.ClearableFileInput): class ImageFileWidget(widgets.ClearableFileInput):
@@ -19,38 +26,19 @@ class ImageFileWidget(widgets.ClearableFileInput):
return context return context
class ImgField(forms.FileField): class ThumbnailImageField(models.ImageField):
widget = ImageFileWidget
default_validators = [
FileExtensionValidator(['jpg', 'jpeg', 'png']),
MaxFilesizeValidator(MAX_UPLOAD_SIZE),
]
def widget_attrs(self, widget):
attrs = super().widget_attrs(widget)
if isinstance(widget, FileInput) and 'accept' not in widget.attrs:
attrs.setdefault('accept', 'image/png,image/jpeg') # image/*
if isinstance(widget, ImageFileWidget):
attrs.update({
'data-upload-limit': readableToInt(MAX_UPLOAD_SIZE),
'data-upload-limit-str': MAX_UPLOAD_SIZE,
'onchange': 'validate_upload_limit(this)',
})
return attrs
class FileWithImagePreview(models.FileField): # use ImageField to omit Pillow
__del_image_on_save = False __del_image_on_save = False
def formfield(self, **kwargs): def formfield(self, **kwargs):
if kwargs['widget'] is AdminFileWidget: kwargs['widget'] = ImageFileWidget
# Override admin widget. Defined by ImgField anyway return super().formfield(**kwargs)
del kwargs['widget']
return super().formfield(**{'form_class': ImgField, **kwargs})
def save_form_data(self, instance, data): def save_form_data(self, instance, data):
if data is False: if data is False:
self.__del_image_on_save = True self.__del_image_on_save = True
if isinstance(data, UploadedFile):
makeThumnail(data, (1200, 900)) # only on create
# on update: django.db.models.fields.files.ImageFieldFile
super().save_form_data(instance, data) super().save_form_data(instance, data)
def pre_save(self, model_instance, add): def pre_save(self, model_instance, add):

View File

@@ -1,4 +1,4 @@
Django==4.2.13 Django>=4.2,<5
Pillow==10.4.0 Pillow==10.4.0
django_colorfield==0.11.0 django_colorfield==0.11.0
django-tinymce==4.1.0 django-tinymce==4.1.0