Reputation: 313
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?
Upvotes: 1
Views: 4383
Reputation: 2213
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.
Upvotes: 2
Reputation: 313
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 = ''
Upvotes: 0
Reputation: 239290
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()
Upvotes: 3
Reputation: 22449
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)
Upvotes: 1