Django imagekit and dynamic paths - django

I'm using imagekit provided at: imagekit
So, I've defined two class model:
class Photo(models.Model):
#photo_wrapper = models.ForeignKey(PhotoWrapper, blank=True, null=True)
original_image = models.ImageField(upload_to='static/photos')
thumbnail = ImageSpec([Adjust(contrast=1.2, sharpness=1.1),
resize.Crop(50, 50)], image_field='original_image',
format='JPEG', quality=90)
num_views = models.PositiveIntegerField(editable=False, default=0)
class IKOptions:
# This inner class is where we define the ImageKit options for the model
spec_module = 'myspecs.specs'
cache_dir = 'static/photos'
image_field = 'original_image'
save_count_as = 'num_views'
class Country(models.Model):
country_name = models.CharField(max_length=250)
country_photo = models.ForeignKey(Photo, blank=True, null=True)
def __unicode__(self):
return '%s' % self.country_name
The problem is that each photo is created in the "static/photos" path.
My intent is to save the image and the thumbnail with a dynamic path, based on the country name..
For example, for the country "Argentina", the dynamic path will be "static/photos/Argentina/"
How can I accomplish that?

It looks like you're mixing two different versions of ImageKit. The newer versions (1.0+) no longer use the inner IKOptions class, so all of that is being ignored. (The save_count_as functionality was also removed.)
If you want to control the cache filename, the ImageSpec constructor accepts a cache_to kwarg which—like ImageField's upload_to—can be a callable. Here's the current documentation for cache_to:
Specifies the filename to use when saving the image
cache file. This is modeled after ImageField's ``upload_to`` and
can be either a string (that specifies a directory) or a
callable (that returns a filepath). Callable values should
accept the following arguments:
- instance -- The model instance this spec belongs to
- path -- The path of the original image
- specname -- the property name that the spec is bound to on
the model instance
- extension -- A recommended extension. If the format of the
spec is set explicitly, this suggestion will be
based on that format. if not, the extension of the
original file will be passed. You do not have to use
this extension, it's only a recommendation.
So you'll just have to create a function that accepts those arguments and returns the path you want, and use that in your model like so:
class Photo(models.Model):
thumbnail = ImageSpec(..., cache_to=my_cache_to_function)

Related

upload_to based off foreign key value

I have an Image model. I want it to upload to a folder depending on which category the user chooses. For example if the user chooses the "apples" category I'd like it to upload to a media folder called "apples".
class Image(models.Model):
image = models.ImageField(upload_to=category)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
You can pass a callable to the category that takes as parameters self and the filename of the original file.
You thus can define this as:
from os.path import join as osjoin
class Image(models.Model):
def image_dir(self, filename):
return osjoin(str(self.category), filename)
image = models.ImageField(upload_to=image_dir)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
Note that here I assume that you have given the Category model a __str__ method. You might however change str(self.category) to for example: self.category.name for example if the Category has a name field, and you want to use that.

How to extract string from CharField in class level?

Because I want the Charfield string to save my Image at specific folder. I want to transfer or extract the string from CharField in Django
I have tried the to_python method it doesn't work in class level.
class Project(models.Model):
filename = models.CharField(max_length=150)
cata = models.CharField(max_length=150)
image = models.ImageField(max_length=100, upload_to= 'ourwork/image/' + str(cata) + '/' + str(filename) , default='ourwork/default/default.png', verbose_name='图片')
def __str__(self):
return self.filename
I want to see the image I uploaded at Django Admin console to show at 'ourwork/project/image' folder
Short answer: use a callable and let the callable calculate the upload_to attribute, based on the field of the model object.
You can use a callable as FileField.upload_to attribute [Django-doc], as the documentation specifies:
upload_to may also be a callable, such as a function. This will
be called to obtain the upload path, including the filename. This
callable must accept two arguments and return a Unix-style path
(with forward slashes) to be passed along to the storage system.
So we can define this as:
def our_upload_to(instance, filename):
return 'ourwork/image/{}/{}'.format(instance.cata, instance.filename)
class Project(models.Model):
filename = models.CharField(max_length=150)
cata = models.CharField(max_length=150)
image = models.ImageField(max_length=100, upload_to=our_upload_to, default='ourwork/default/default.png', verbose_name='图片')
def __str__(self):
return self.filename
We thus here calculate the upload_to parameter based on the instance (first parameter), and ignore the filename of that was originally given to the file by the user that uploaded the file.

Changing file name on upload using id in Django ImageField

In this model, I want to change the name of the file uploaded in ImageField
class Product(models.Model):
image = models.ImageField(upload_to=content_file_name)
name = models.CharField(max_length=100)
amount = models.PositiveIntegerField()
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
To change the name of image I'm using this function
def content_file_name(instance, filename):
ext = filename.split('.')[-1]
filename = '%s.%s' % (instance.id, ext)
return os.path.join('products', filename)
but the name of my image is None, if I use other fields like 'name', it works. What should I do to change the name with id? Thanks!
The instance's id is not yet created, because the upload_to function is called before the new object is first written to the database.
In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field.
Emphasis from the Django docs
Two alternatives:
Use a uuid.uuid4() value, its easy to create and as unique as the pk.
Another suggestion, if you care about search engines and SEO, use a slugify(instance.name) so that your images can be easier found in the image search of search engines.

How to change upload_to parameter of ImageField based on field name in Django?

I would like to upload images to the media root based on the field values given by the Django admin user. Here is the code that I've written and I know that the upload_to parameter is causing the problem. But I don't know how to make it work.
models.py
class Info(models.Model):
file_no = models.CharField(max_length=100)
date = models.DateField()
area = models.IntegerField(default=0.00)
mouja = models.CharField(max_length=100)
doc_type_choices = (
('deed', 'Deed'),
('khotian', 'Khotian'),
)
doc_type = models.CharField(max_length=50,
choices=doc_type_choices,
default='deed')
doc_no = models.CharField(max_length=50)
def __unicode__(self):
return self.file_no
class Image(models.Model):
info = models.ForeignKey('Info')
content = models.ImageField(upload_to=self.info.mouja/self.info.doc_type)
def __unicode__(self):
return self.info.file_no
Whenever I run python manage.py makemigrations it shows NameError: name 'self' is not defined
Thanks in advance for any help!
In the upload_to keyword you would need to provide a function that you will define, for instance:
def path_file_name(instance, filename):
return '/'.join(filter(None, (instance.info.mouja, instance.info.doc_type, filename)))
class Image(models.Model):
content = models.ImageField(upload_to=path_file_name)
From Django documentation: Model field reference:
This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename. This callable must be able to accept two arguments, and return a Unix-style path (with forward slashes) to be passed along to the storage system.
Within this callable, which in the particular case is path_file_name function, we build a path from the instance field which is the particular record of Image model.
The filter function removes any None items out of the list and the join function constructs the path by joining all list items with /.
Here is the original code that worked. Just in case anyone needs it.
def path_file_name(instance, filename):
return '/'.join(filter(None, (instance.info.mouja, instance.info.doc_type, filename)))

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