Changing file name on upload using id in Django ImageField - django

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.

Related

Dynamically naming an image file with another field name in Django2

I am trying to save an image file with the name changed to that of another field in the same form.
After some experimentation, it works well by using a handler function in the model, just when the object has been returned to the model for saving. I deconstruct the file object and can assign it a name that I want, However, I am not able to deconstruct the Charfield object and dynamically pass the first field name to the image file.
from django.db import models
import os
#handler function to customise file name.
def photo_path(instance, filename):
basefilename, file_extension= os.path.splitext(filename)
return '{add}/{room}/{basename}{ext}'.format
(add='my_Add', room="should_Be_room_type", basename= basefilename, ext= file_extension)
And the model is:
class Room(models.Model):
room_type = models.CharField( max_length=50) # i.e bedroom /living room etc
room_size = models.CharField( max_length=50)
img = models.ImageField( upload_to=photo_path, null=True, blank=True)
def __str__(self):
return self.room_type
in your case, the argument instance would be your Room instance, and you can use it to recover room_type and room_size. As the instance won't be created until after the image uploads, the only thing that won't be available on photo_path will be instance.id, but you don't need it.
Your function then, can be written as:
def photo_path(instance, filename):
basefilename, file_extension = os.path.splitext(filename)
return '{add}/{room}/{basename}{ext}'.format
(add='my_Add', room=instance.room_type, basename=basefilename, ext=file_extension)
Thanks, I ended up solving it in the view.py by using
my_room_type = request.POST['room_type']
initial_obj = form.save(commit=False)
initial_obj.save()
The idea was to get the value entered for the 'room_type' and print it on the image. It now works thanks.

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)))

saving an image as [self.id].jpg on DJANGO admin

I need an admin on django to be able to upload an image that should be saved as /path/{self.id}.jpg
So far I have a database with id,status,title fields and a model with id,status,title,THUMB fields:
class MEL(models.Model):
id = models.AutoField(primary_key=True, editable=False)
status = models.IntegerField(choices=( (0, 'inactive'), (1, 'active') ), default=1)
title = models.TextField(verbose_name='Título')
thumb = models.ImageField(upload_to=upload_path)
class Meta:
db_table = u'MEL'
The problem is that the image is uploaded previously to the model being saved, so I can't save it to "self.id" at this moment.
I think I could save it to /tmp/{uuid} and then renaming it post-save, probably something like:
def upload_path(self, filename):
self.file_uuid = uuid.uuid4()
return '/tmp/' + self.file_uuid
and then a post-save that renames it and delete it from /tmp/
Or I could try overriding this model's save() method to first call super().save(), then process the image upload (which is in a ImageFieldFile object) and rename it to self.id
suggestions?
thanks
You should be able to change the filename using upload_to. I say this because I have done it in projects and the django documentation says so:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.FileField.upload_to
The third paragraph down of that link says this: "This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename." [emphasis added]. I'm not trying to be sarcastic I'm just showing that this is and should be possible so something else must be going on.
try something like this. The problem could be that you were leaving off the extension:
def upload_path(self, filename):
basename, extension = os.path.splitext(filename)
return '/'.join(["path",("%s%s" % (self.id, extension))])

Pathname to the image field in Django

I have this model which has Image field to be uploaded. It has a foreign key reference to another class.
from django.template.defaultfilters import slugify
def upload_to(path, attribute):
def upload_callback(instance, filename):
return '%s%s/%s' % (path, unicode(slugify(getattr(instance, attribute))), filename)
return upload_callback
class Data(models.Model):
place = models.CharField(max_length=40)
typeOfProperty = models.CharField(max_length=30)
typeOfPlace = models.CharField(max_length=20)
price = models.IntegerField()
ownerName = models.CharField(max_length=80)
class ImageData(models.Model):
property = models.ForeignKey(Data, related_name='images')
image = models.ImageField(upload_to = upload_to('image/', 'ownerName'),blank=True,null=True)
def __unicode__(self):
return self.property.ownerName
I have refered this This Web Page to create a dynamic field for images to be stored.
My doubt is can I use the onerName as the attribute in (as the ownerName is in the super class) :
image = models.ImageField(upload_to = upload_to('image/', 'ownerName'),blank=True,null=True)
How does Django consider this request that is need to be served?
Please can anyone explain me this?
'ownerName' is not going to work. It's quite complicated to do the definition of what you want to save in the ImageField directly. Maybe you should do something like this:
def upload_to(path):
def upload_callback(instance, filename):
return '%s%s/%s' % (path, unicode(slugify(instance.property.ownerName), filename)
return upload_callback
If you really want to make it as dynamic as possible you have to pass something like 'property.ownerName' to the function, split the string, retrieve attrtibute property from ImageData instance and then attribute ownerName from its foreign key instance.
Though I think this makes things way to complicated and you better define extra functions for different use cases.

File uploads in Django: prevent FileField from writing the full path to the database

I'm building a software repository on top of the Django framework. Because it will contain a lot of files, i want it to make some sense when looking at it through a file manager. So i grouped the files first by the URL of a program they belong to and then by first two letters of that URL. Here's how it looks:
The schema looks like this:
class File(models.Model):
# If called like upload_to, don't put a slash in front of the result
# because we already have one in settings.MEDIA_ROOT
def get_absolute_url(self, filename=None):
return '%sfiles/%s/%s/%s' % ('' if filename else '/',
self.download.url[:2],
self.download.url,
filename or self.name)
name = models.FileField(upload_to=get_absolute_url, max_length=255)
size = models.IntegerField()
title = models.CharField(blank=True, max_length=255)
download = models.ForeignKey('Download', related_name='files')
class Download(models.Model):
url = models.SlugField(unique=True, max_length=255)
title = models.CharField(max_length=255)
There is, however, a minor problem: FileField will store the entire generated path instead of just the name, which i would rather like to avoid. Is there any way to override (probably in my own field class) what FileField writes to the database and how it reconstructs the path after loading the raw field?
name = models.FileField(upload_to=get_absolute_url, max_length=255)
upload_to usually looks like this
upload_to ='./files'
It will be stored as ./files/your.file in the db
and as <MEDIA_ROOT>/files/your.file at your disk
You can change the upload_to-String to whatever fits best for you programatically
upload_to ='./files'+'/subdir'
but it should start with './'
FileField-Reference
get_absolute_url() should return a url like http://domain.com/sitemedia/files/your.file
EDIT:
to remove the path from the file name you could do string operations in File.save() like
def save(self, force_insert=False, force_update=False):
self.name = self.name[self.name.rfind('/')+1:]
super(File, self).save(force_insert, force_update)