mirror of
https://github.com/dkmstr/openuds.git
synced 2025-02-09 09:57:36 +03:00
Updated model saving to use "setattr" instead of "__dict__.update". Allow use of properties, etc...
This commit is contained in:
parent
3451719675
commit
a23ca0eb73
@ -73,14 +73,16 @@ class Images(ModelHandler):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def beforeSave(self, fields: typing.Dict[str, typing.Any]) -> None:
|
def beforeSave(self, fields: typing.Dict[str, typing.Any]) -> None:
|
||||||
fields['data'] = Image.prepareForDb(Image.decode64(fields['data']))[2]
|
fields['image'] = fields['data']
|
||||||
|
del fields['data']
|
||||||
|
#fields['data'] = Image.prepareForDb(Image.decode64(fields['data']))[2]
|
||||||
|
|
||||||
def afterSave(self, item: 'Model') -> None:
|
def afterSave(self, item: 'Model') -> None:
|
||||||
item = ensure.is_instance(item, Image)
|
item = ensure.is_instance(item, Image)
|
||||||
# Updates the thumbnail and re-saves it
|
# Updates the thumbnail and re-saves it
|
||||||
logger.debug('After save: item = %s', item)
|
logger.debug('After save: item = %s', item)
|
||||||
item.updateThumbnail()
|
#item.updateThumbnail()
|
||||||
item.save()
|
#item.save()
|
||||||
|
|
||||||
def getGui(self, type_: str) -> typing.List[typing.Any]:
|
def getGui(self, type_: str) -> typing.List[typing.Any]:
|
||||||
return self.addField(
|
return self.addField(
|
||||||
|
@ -1115,7 +1115,9 @@ class ModelHandler(BaseModelHandler):
|
|||||||
for v in self.remove_fields:
|
for v in self.remove_fields:
|
||||||
if v in args:
|
if v in args:
|
||||||
del args[v]
|
del args[v]
|
||||||
item.__dict__.update(args) # Update fields from args
|
for k, v in args.items():
|
||||||
|
setattr(item, k, v)
|
||||||
|
# item.__dict__.update(args) # Update fields from args
|
||||||
|
|
||||||
# Now if tags, update them
|
# Now if tags, update them
|
||||||
if isinstance(item, TaggingMixin):
|
if isinstance(item, TaggingMixin):
|
||||||
@ -1156,7 +1158,7 @@ class ModelHandler(BaseModelHandler):
|
|||||||
raise exceptions.NotFound('Item not found') from None
|
raise exceptions.NotFound('Item not found') from None
|
||||||
except IntegrityError: # Duplicate key probably
|
except IntegrityError: # Duplicate key probably
|
||||||
raise exceptions.RequestError('Element already exists (duplicate key error)') from None
|
raise exceptions.RequestError('Element already exists (duplicate key error)') from None
|
||||||
except (exceptions.SaveException, udsexceptions.validation.ValidationError) as e:
|
except (exceptions.SaveException, udsExceptions.validation.ValidationError) as e:
|
||||||
raise exceptions.RequestError(str(e)) from e
|
raise exceptions.RequestError(str(e)) from e
|
||||||
except (exceptions.RequestError, exceptions.ResponseError):
|
except (exceptions.RequestError, exceptions.ResponseError):
|
||||||
raise
|
raise
|
||||||
|
@ -325,7 +325,7 @@ class Command(BaseCommand):
|
|||||||
gallery[galleryItem.name] = {
|
gallery[galleryItem.name] = {
|
||||||
'size': f'{galleryItem.width}x{galleryItem.height}',
|
'size': f'{galleryItem.width}x{galleryItem.height}',
|
||||||
'stamp': galleryItem.stamp,
|
'stamp': galleryItem.stamp,
|
||||||
'length': len(galleryItem.data),
|
'length': galleryItem.length,
|
||||||
}
|
}
|
||||||
|
|
||||||
tree[counter('GALLERY')] = gallery
|
tree[counter('GALLERY')] = gallery
|
||||||
|
@ -28,9 +28,11 @@
|
|||||||
"""
|
"""
|
||||||
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||||
"""
|
"""
|
||||||
|
from email.mime import base
|
||||||
import io
|
import io
|
||||||
import codecs
|
import base64
|
||||||
import logging
|
import logging
|
||||||
|
from operator import ne
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
|
||||||
@ -41,8 +43,8 @@ from django.http import HttpResponse
|
|||||||
|
|
||||||
|
|
||||||
from .uuid_model import UUIDModel
|
from .uuid_model import UUIDModel
|
||||||
from ..core.util.model import getSqlDatetime
|
from uds.core.util.model import getSqlDatetime
|
||||||
|
from uds.core import consts
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -86,17 +88,7 @@ class Image(UUIDModel):
|
|||||||
app_label = 'uds'
|
app_label = 'uds'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def encode64(data: bytes) -> str:
|
def resizeAndConvert(image: PIL.Image.Image, size: typing.Tuple[int, int]) -> typing.Tuple[int, int, bytes]:
|
||||||
return codecs.encode(data, 'base64').decode().replace('\n', '')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def decode64(data64: str) -> bytes:
|
|
||||||
return codecs.decode(data64.encode(), 'base64')
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def resizeAndConvert(
|
|
||||||
image: PIL.Image.Image, size: typing.Tuple[int, int]
|
|
||||||
) -> typing.Tuple[int, int, bytes]:
|
|
||||||
"""
|
"""
|
||||||
Resizes an image to the given size
|
Resizes an image to the given size
|
||||||
"""
|
"""
|
||||||
@ -110,10 +102,8 @@ class Image(UUIDModel):
|
|||||||
try:
|
try:
|
||||||
stream = io.BytesIO(data)
|
stream = io.BytesIO(data)
|
||||||
image = PIL.Image.open(stream)
|
image = PIL.Image.open(stream)
|
||||||
except (
|
except Exception: # Image data is incorrect, replace as a simple transparent image
|
||||||
Exception
|
image = PIL.Image.new('RGBA', Image.MAX_IMAGE_SIZE)
|
||||||
): # Image data is incorrect, replace as a simple transparent image
|
|
||||||
image = PIL.Image.new('RGBA', (128, 128))
|
|
||||||
|
|
||||||
# Max image size, keeping aspect and using antialias
|
# Max image size, keeping aspect and using antialias
|
||||||
return Image.resizeAndConvert(image, Image.MAX_IMAGE_SIZE)
|
return Image.resizeAndConvert(image, Image.MAX_IMAGE_SIZE)
|
||||||
@ -123,28 +113,14 @@ class Image(UUIDModel):
|
|||||||
"""
|
"""
|
||||||
Returns the value of the image (data) as a base 64 encoded string
|
Returns the value of the image (data) as a base 64 encoded string
|
||||||
"""
|
"""
|
||||||
return Image.encode64(self.data)
|
return base64.b64encode(typing.cast(bytes, self.data)).decode()
|
||||||
|
|
||||||
@data64.setter
|
|
||||||
def data64(self, value: str) -> None:
|
|
||||||
"""
|
|
||||||
Sets the value of image (data) from a base 64 encoded string
|
|
||||||
"""
|
|
||||||
self.data = Image.decode64(value)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def thumb64(self) -> str:
|
def thumb64(self) -> str:
|
||||||
"""
|
"""
|
||||||
Returns the value of the image (data) as a base 64 encoded string
|
Returns the value of the image (data) as a base 64 encoded string
|
||||||
"""
|
"""
|
||||||
return Image.encode64(self.thumb)
|
return base64.b64encode(self.thumb).decode()
|
||||||
|
|
||||||
@thumb64.setter
|
|
||||||
def thumb64(self, value: str) -> None:
|
|
||||||
"""
|
|
||||||
Sets the value of image (data) from a base 64 encoded string
|
|
||||||
"""
|
|
||||||
self.thumb = Image.decode64(value)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def image(self) -> PIL.Image.Image:
|
def image(self) -> PIL.Image.Image:
|
||||||
@ -157,6 +133,49 @@ class Image(UUIDModel):
|
|||||||
except Exception: # Image data is incorrect, fix as a simple transparent image
|
except Exception: # Image data is incorrect, fix as a simple transparent image
|
||||||
return PIL.Image.new('RGBA', Image.MAX_IMAGE_SIZE)
|
return PIL.Image.new('RGBA', Image.MAX_IMAGE_SIZE)
|
||||||
|
|
||||||
|
@image.setter
|
||||||
|
def image(self, value: typing.Union[bytes, str, PIL.Image.Image]) -> None:
|
||||||
|
"""Set image from bytes, base64 string or PIL Image
|
||||||
|
Bytes: raw data
|
||||||
|
String: base64 encoded data
|
||||||
|
Image: PIL Image
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (typing.Union[bytes, str, Image.Image]): Image data
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: Invalid image type
|
||||||
|
|
||||||
|
Note:
|
||||||
|
This method also creates the thumbnail
|
||||||
|
Not saved to database until save() is called
|
||||||
|
"""
|
||||||
|
data: bytes = b''
|
||||||
|
if value:
|
||||||
|
if isinstance(value, bytes):
|
||||||
|
data = value
|
||||||
|
elif isinstance(value, str):
|
||||||
|
data = base64.b64decode(value)
|
||||||
|
elif isinstance(value, PIL.Image.Image):
|
||||||
|
with io.BytesIO() as output:
|
||||||
|
value.save(output, format='PNG')
|
||||||
|
data = output.getvalue()
|
||||||
|
else:
|
||||||
|
raise ValueError('Invalid image type')
|
||||||
|
|
||||||
|
self.width, self.height, self.data = Image.prepareForDb(data)
|
||||||
|
|
||||||
|
# Setup thumbnail
|
||||||
|
with io.BytesIO(data) as input:
|
||||||
|
with PIL.Image.open(input) as img:
|
||||||
|
img.thumbnail(Image.THUMBNAIL_SIZE, PIL.Image.LANCZOS)
|
||||||
|
with io.BytesIO() as output:
|
||||||
|
img.save(output, format='PNG')
|
||||||
|
self.thumb = output.getvalue()
|
||||||
|
else:
|
||||||
|
self.data = consts.images.DEFAULT_IMAGE
|
||||||
|
self.thumb = consts.images.DEFAULT_THUMB
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self) -> typing.Tuple[int, int]:
|
def size(self) -> typing.Tuple[int, int]:
|
||||||
"""
|
"""
|
||||||
@ -164,24 +183,12 @@ class Image(UUIDModel):
|
|||||||
"""
|
"""
|
||||||
return self.width, self.height
|
return self.width, self.height
|
||||||
|
|
||||||
def updateThumbnail(self) -> None:
|
@property
|
||||||
img = self.image
|
def length(self) -> int:
|
||||||
_, _, self.thumb = Image.resizeAndConvert(img, Image.THUMBNAIL_SIZE)
|
|
||||||
|
|
||||||
def _processImageStore(self) -> None:
|
|
||||||
self.width, self.height, self.data = Image.prepareForDb(self.data)
|
|
||||||
self.updateThumbnail()
|
|
||||||
|
|
||||||
def storeImageFromBinary(self, data: bytes) -> None:
|
|
||||||
self.data = data
|
|
||||||
self._processImageStore()
|
|
||||||
|
|
||||||
def storeImageFromBase64(self, data64: str):
|
|
||||||
"""
|
"""
|
||||||
Stores an image, passed as base64 string, resizing it as necessary
|
Returns the image size
|
||||||
"""
|
"""
|
||||||
self.data64 = data64
|
return len(self.data)
|
||||||
self._processImageStore()
|
|
||||||
|
|
||||||
def imageResponse(self) -> HttpResponse:
|
def imageResponse(self) -> HttpResponse:
|
||||||
return HttpResponse(self.data, content_type='image/png')
|
return HttpResponse(self.data, content_type='image/png')
|
||||||
|
Loading…
x
Reference in New Issue
Block a user