Reputation: 75
I'm creating a news blog, so I decided to add a profile image. I was thinking, how to create image thumbnail better and decide to use percent resizing.
def save(self, *args, **kwargs):
image = Image.open(self.image) # Открываем картинку
width, height = image.size # Получаем размеры картинки
new_image = BytesIO() # Создаем байтовое представление
resize = (width * (height // 10 * 5) // height, height // 10 * 5) # Изменение по высоте
if width > height: # Если горизонтальная картинка
resize = (width // 10 * 5, height * (width // 10 * 5) // width) # Изменение по ширине
image.thumbnail(resize, resample=Image.ANTIALIAS) # Делаем миниатюру картинки
image = image.convert('RGB') # Убираем все лишние каналы
image.save(new_image, format='JPEG', quality=90) # Конвертируем в JPEG, ибо мало весит
new_image.seek(0) # Возвращение в начало файла
name = f'{self.image.name.split(".")[0]}.jpeg' # Имя файла
# Перезапись файла в базе данных
self.image = InMemoryUploadedFile(
new_image, 'ImageField', # Картинка, поля сохранения
name, 'image/jpeg', # Имя картинки, содержание
getsizeof(new_image), None # Размер, доп инфа
)
# Сохранение через другой save класса
super(KvantUser, self).save(*args, **kwargs)
So, as you can see, I take only a half of the image size. It helps to keep good quality of the picture and reduce its size. But this method cause another problem.
Every time, when save()
method called, image become smaller and smaller...
I've tried to rewrite my change form, but it didn't help.
As I knew, Django call save()
method every time I change model, or login in system. So, I need help to solve this problem. Maybe it's better to create a fixed thumbnail, or you know a better way to do it. Feel free to suggest any ideas!
My model.py
def set_default_image():
bucket = S3Boto3Storage()
if not bucket.exists('default/user/user.png'):
with open(join(settings.MEDIA_ROOT + '/default/user.png'), 'b+r') as f:
bucket.save('default/user/user.png', f)
return 'default/user/user.png'
def get_path(instance, filename):
return f'user/{instance.username}/{filename}'
class KvantUser(AbstractUser):
name = models.CharField(max_length=100)
surname = models.CharField(max_length=100)
patronymic = models.CharField(max_length=100)
permission = models.CharField(choices=permission, max_length=100)
color = models.CharField(max_length=100, choices=color, default='blue')
theme = models.CharField(max_length=100, choices=theme, default='light')
image = models.ImageField(upload_to=get_path, default=set_default_image)
My forms.py
class KvantUserCreationForm(UserCreationForm):
class Meta(UserCreationForm):
model = KvantUser
fields = ('username', 'email', 'password', 'name', 'surname', 'patronymic', 'image')
class KvantUserChangeForm(UserChangeForm):
class Meta:
model = KvantUser
fields = ('username', 'email', 'password', 'name', 'surname', 'patronymic', 'image')
class KvantUserLoginForm(forms.Form):
username = forms.CharField(max_length=150)
password = forms.CharField(max_length=150)
def save(self, request):
username = self.cleaned_data['username'] # Получение логина
password = self.cleaned_data['password'] # Получение пароля
if KvantUser.objects.filter(username=username).exists(): # Проверка существования акаунта
user = authenticate(username=username, password=password) # Попытка авторизации
if user is not None: # Если попытка удачна, то авторизуй и верни пользователя
login(request, user)
return user
messages.error(request, 'Ошибка авторизации!') # Сообщение об ощибки
return None
P.S If you need another file, feel free to ask.
Upvotes: 2
Views: 91
Reputation: 21807
If you only want to create the thumbnail when the KvantUser
instance is created you can check if the pk
exists before using your logic for resizing the image:
def save(self, *args, **kwargs):
if self.pk is None:
# Your code to make the thumbnail here
super(KvantUser, self).save(*args, **kwargs)
But there is a better way, that is to put this logic in the form itself, since you have multiple forms for this model, write a mixin and inherit that in these forms:
class ImageThumbnailFormMixin:
def clean_image(self):
f = self.cleaned_data.get('image')
if not f:
return f
image = f.image # A PIL Image object that Django has annotated here
# Make the thumbnail here with the `image` object
image.save()
return f
class KvantUserCreationForm(ImageThumbnailFormMixin, UserCreationForm):
class Meta(UserCreationForm):
model = KvantUser
fields = ('username', 'email', 'password', 'name', 'surname', 'patronymic', 'image')
class KvantUserChangeForm(ImageThumbnailFormMixin, UserChangeForm):
class Meta:
model = KvantUser
fields = ('username', 'email', 'password', 'name', 'surname', 'patronymic', 'image')
Upvotes: 2