How to store thumbnails in the same folder with Django ImageKit? - django

Does anyone have experience using ImageKit to manage thumbnails?
I currently have the following in my models.py:
class Item(models.Model):
id = models.AutoField(primary_key=True)
owner = models.ForeignKey(
get_user_model(),
on_delete=models.SET_NULL,
null=True,
blank=True
)
image = ProcessedImageField(
upload_to=image_upload,
blank=True,
validators=[validate_image],
format='JPEG',
help_text="Max file size is 3 MB."
)
image_thumbnail = ImageSpecField(
source='image',
processors=[ResizeToFill(50, 50)],
format='JPEG',
options={'quality': 60}
)
I'd like to rename the thumbnail and store it in a particular folder (not the CACHE/images/ folder that ImageKit defaults to), but can't figure out how to do that (and adding an "upload_to" to the thumbnail gives me an error). All help greatly appreciated! Thank you!

According to the docs:
ImageSpecFields, on the other hand, are virtual—they add no fields to your database and don’t require a database. This is handy for a lot of reasons, but it means that the path to the image file needs to be programmatically constructed based on the source image and the spec.
You might just want to stick to the ProcessedImageFIeld if you don't want your files to be stored in a cache folder.

Related

Delete Image on S3 bucket before uploading new image with the same name

I have a model, that on save, it uploads my image to my S3 bucket. But I'm having some trouble when I want to reupload an image with the same name. (Example: when a logo updates it needs to be reuploaded)
Because the image already exists, Django extends the pathname with it's own generated extention to make it unique. We don't want that, we want to delete the existing image before uploading the new image. That way, the extention is no more.
I've tried removing my image first with the pre_save signal, but that just makes my imagefield empty
#receiver(pre_save, sender=geo_models.Logo)
def remove_file_from_s3(sender, instance, using, **kwargs):
instance.png.delete(save=False)
Any way of doing this?
Model:
class Logo(models.Model):
logo_type_choices = Choices(
('ENTITY', _('Entity')),
('BRAND', _('Brand')),
)
class Meta:
verbose_name = _('logo')
verbose_name_plural = _('logos')
png = models.ImageField(
verbose_name='{0} {1}'.format('png', _('image')),
upload_to=get_upload_loc_png,
validators=[validators.validate_png_extension],
storage=storage,
max_length=200,
blank=True,
null=True,
)
logo_type = models.CharField(choices=logo_type_choices, max_length=20)
django-storages has an optional setting AWS_S3_FILE_OVERWRITE.
By default, it is set to True (reference). That is, by default files with the same name will overwrite each other. Set this to False to have extra characters appended.

Saving images names into the database - Django

I have the folllowing class model in my Django website:
class Buy(models.Model):
category = models.ForeignKey(Category, related_name='sell', on_delete=models.CASCADE)
title = models.CharField(max_length=100)
image = models.FileField()
image2 = models.FileField(blank=True)
description = models.CharField(max_length=300)
date = models.DateField(default=timezone.now)
buy_price = models.DecimalField(max_digits=6, decimal_places=2)
sell_price = models.DecimalField(max_digits=6, decimal_places=2)
seller = models.ForeignKey(Seller, on_delete=models.PROTECT)
showcase = models.BooleanField(default=False)
As you can see, I store photos files with 2 fields: image and image2. But now my client requested me to add more photos. My doubt is:
Should I continue adding new fields to this class, for example, image3, image4, image5 and so on? The problem I see: not every records will have so many photos and the most of them will become "empty".
Should I only upload the new photos without saving their names into the database? In this way, the new photos should follow some name related to the image class field. I mean, unique_photo_1.jpg goes inside the image field, unique_photo_2.jpg is not saved into the database but is related to this field, as well as the unique_photo_3.jpg.
What is the best practice?
Thank you!
On #1, the best practice is to follow database normalization principles, and create a separate Image model that relates back to your Buy model. If you anticipate that the images may be reused in several Buy model instances, use many-to-many relationships; otherwise, use many-to-one (i.e. ForeignKey). That means removing image and image2 from your Buy model, and then creating e.g.:
class Image(models.Model):
image = models.FileField()
image_type = models.CharField()
buy = models.ForeignKey(Buy, on_delete=models.PROTECT)
By #2, if you mean you're considering skipping using FileField or ImageField to instead write code that will search for files in some storage space, then that doesn't sound like a good idea, because then you're divorcing your file (meta)data from the rest of your database contents. Using FiledField/ImageField will also make it much easier to use storage backends such as AWS S3.

I use two interconnected ChainedForeignKey fields, but they don't. why?

my problem:
I have three models. il (province), ilce (district) and mahalle (neighborhood).
I filter with smart-select. works smoothly in the entry of information. When I looked at the database, I saw that mahalle (neighborhood) data was recorded. but the mahalle (neighborhood) widget sounds empty.
my models:
class il(models.Model):
adi = models.CharField(max_length=20)
class ilce(models.Model):
ill = models.ForeignKey(il, on_delete=models.CASCADE)
adi = models.CharField(max_length=35)
class mahalle(models.Model):
ilcee = models.ForeignKey(ilce, on_delete=models.CASCADE)
adi = models.CharField(max_length=50)
class User(AbstractUser):
username = None
email = models.EmailField(_('email address'), unique=True)
.......
kurum_il = models.ForeignKey('il', on_delete=models.SET_NULL, null=True, blank=False)
kurum_ilce = ChainedForeignKey('ilce', chained_field="kurum_il", chained_model_field="ill", show_all=False, sort=False, null=True, blank=False)
kurum_mahalle = ChainedForeignKey('mahalle', chained_field="kurum_ilce", chained_model_field='ilcee', show_all=False, sort=False, null=True, blank=False)
Does not appear on the Admin page even though I enter and save neighborhood information
related screenshot
Django-smart-selects looks long unmaintained with last release in 2018.
However there are few issues raised / discussed for it that may relate to your question, one of them #237. As a solution it has this Pull Request with little change to .js file (actually it just comments out one line).
As it is not yet included in official release, you can apply these changes manually and provide new .js file to override package one:
copy chainedfk.js from master branch to your project
place it at 'smart-selects/admin/js/chainedfk.js' path in your directory for static files:
place inside static directory in your app and make this app appear before smart_selects in INSTALLED_APPS
or use same static directory or at another path by your preference but specify path to static directory in STATICFILES_DIRS (more preferred, not depend on order in INSTALLED_APPS)
edit this file, apply changes of this Pull Request and any other changes of your choice.

How do I only accept uploaded images with a 1:1 (square) aspect ratio and throw an error otherwise?

The admin is able to upload an image but I would like to restrict it to only being a square image.
Here is my models.py file:
class Author(models.Model):
author_name = models.CharField(max_length=200)
author_image = models.ImageField(upload_to=upload_location,
null=True,
blank=True,)
author_bio = models.TextField()
def __str__(self):
return self.author_name
ImageField has height_field and width_field properties, but according to the docs, those only get auto-populated after the image is saved.
In order to do it before the image is uploaded, I think you're going to need jQuery. Check out this question/answer, as it seems like what you want to do. You would alter that code to compare that width == height to check for perfect squareness. AJAX would give you the option of the user uploading the image without the page needing to reload.

Django Model store image file size

I am using Django 1.6. I have a model for uploading image files that looks like this.
class Image(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
url = models.ImageField(upload_to=get_image_path,
null=True,
blank=True,
height_field = 'height',
width_field = 'width',
verbose_name='Image')
height = models.IntegerField(blank=True)
width = models.IntegerField(blank=True)
size = models.IntegerField(blank=True)
format = models.CharField(max_length=50)
caption = models.CharField(max_length=255)
def clean(self):
self.size = self.url.size
class Meta:
db_table = 'image'
As you can see, I am storing the size of the image when the clean() method is called. This works for what I want to do, but is this best practise? Is there a better way to automatically save the image's file size when saving?
The second part of my question is how can I get the content type as well?
Thanks,
Mark
Model.clean() should be used for validation - do not use it to update/save the data, but rather use it to correct any invalid data (or throw an exception/error message).
You may want to consider not even storing the size of the image in the database, given that you can access it from the ImageField - it eliminates the possibility of the data becoming inconsistent as it changes over time.
I believe this question/answer should address your second question.
For the first question
Check out the Python Imaging Library PIL on this thread.
from PIL import Image
im=Image.open(filepath)
im.size # (width,height) tuple
For the second question
HttpRequest.META, more specifically HttpRequest.META.get('CONTENT_TYPE')
from this thread