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.