django - set the upload_to in the view - django

I have a model for storing files:
class AFile(models.Model):
path = models.CharField(max_length=256)
name = models.CharField(max_length=256)
file = models.FileField(upload_to=get_path)
there are many views that save files. I want a seperate path for each. so I put path in the model and use that in the get path function. like so:
afile = AFile(path='blah/foo/', name='filex.jpg')
afile.save()
so the file is in the right spot. But I don't really want to store the path and name field in my database, its only there to generate a path. any way to achieve this same thing without extra model fields?

The problem here is that upload_to is only available when defining the FileField or ImageField on the model. Any subsequent access to the field returns a FieldFile instance, which doesn't have access to the defined upload_to. Long and short, there's no way to alter the method after it's initially defined.
However, you might be able to do a sort of end-run around it. Note that I haven't actually tried this, but it should work:
First define a method on your model that will have the simple task of setting an instance variable on the model:
def set_upload_to_info(self, path, name):
self.upload_to_info = (path, name)
Then, inside your upload_to method, you can test for the presence of these attributes and use them if they are:
def my_upload_to(instance, filename):
if hasattr(instance, 'upload_to_info'):
path, name = instance.upload_to_info
# do something and return file path
else:
# standard upload_to bit here
Then in your view, you just need to call the method you create before you save the model:
afile.set_upload_to_info(path, name)
afile.save()

upload to argument can be changed in view by changing field.upload_to attribute of FileField before saving model. In my case I was using class based views together with forms. So before model instance. I used below code to change upload to path.
with transaction.atomic():
model_instance = form.save(commit=False)
model_instance.creator = self.request.user
model_instance.img_field.field.upload_to = 'directory/'+model_instance.name+'/logo'
self.object = form.save()
In short if your image field is named as imageupload, change imageupload.field.upload_to accordingly to point to the path you need. Please let know if this approach solved your issue.

Why don't you generate the path from the instance?
def generate_path(instance, filename):
return os.path.join("hardcoded_prefix", instance.name, filename)
class AFile(models.Model):
name = models.CharField(max_length=256)
file = models.FileField(upload_to=generate_path)

solution is to put in some non-persistent fields and still refer to them in the get_path method
class AFile(models.Model):
name = models.CharField(max_length=256)
file = models.FileField(upload_to=get_path)
path = ''

Related

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

How and where do I handle file uploads from django admin?

So ive read over the docs and I have come out a little confused. I have a model as such
class Image(models.Model):
name = models.CharField(max_length=80)
file = models.ImageField(upload_to = 'project_images')
description = models.CharField(max_length=30)
def __unicode__(self):
return self.name
The handling of the file uploads are done through the admin interface, which works but I need to do a few more things to the data based on other fields present when the upload is committed.
Basically the current directory is project_images what i want to do is when saved the images must be placed in ---> project_images/<year>/<month>. The file path saved must reflect this when saved in the database and the filename must also be saved in the name field.
I understand the logic behind doing this;
Check post
Check valid (the ImageField takes care of this already i assume)
Get filename
Get year and month (numbers)
Check if directories exist
If directories dont exist create it, if they do use them
Set the name to the filename
upload and save all
Where am i supposed to specify this? In the model under a save method?
Sorry if this is specified in the docs but this is one area of the docs which just confused me.
Thanks
from django.db import models
import datetime
import os
import uuid
# Create your models here.
def get_file_path(instance,filename):
ext=filename.split('.')[-1]
filename="%s.%s" % (uuid.uuid4(),ext)
return os.path.join(instance.directory_string_var,filename)
class Image(models.Model):
file=models.ImageField(upload_to=get_file_path)
now=datetime.datetime.now()
directory_string_var = 'image/%s/%s/%s/'%(now.year,now.month,now.day)
change your model to above one.
this saves your file with a random name in the folder media/year/month/day.
if you don't want filename to be random just comment out
ext = filename.split('.')[-1] #and
filename="%s.%s" % (uuid.uuid4(),ext)
check this:
how to create year/month/day structure when uploading files with django
So in your model, you can just do:
class Image(models.Model):
name = models.CharField(max_length=80)
file = models.ImageField(upload_to = 'project_images/%Y/%m')
description = models.CharField(max_length=30)
def __unicode__(self):
return self.name
The '%Y/%m' part of upload_to is strftime formatting; '%Y' is the four-digit year and '%m' is the two-digit month
You must check this to:
http://scottbarnham.com/blog/2007/07/31/uploading-images-to-a-dynamic-path-with-django/
I Hope this helped

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.