django - set the upload_to in the view
Asked Answered
M

4

1

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?

Maltose answered 3/8, 2012 at 13:9 Comment(2)
possible duplicate of Dynamic File Path in DjangoSecund
similar yes but the solution in that case was to use information from the model. my question is how do that with information not contained in the model.Maltose
W
3

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()
Wonacott answered 3/8, 2012 at 15:11 Comment(0)
I
2

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.

Irrational answered 13/10, 2016 at 10:20 Comment(0)
H
1

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)
Homeric answered 3/8, 2012 at 13:18 Comment(2)
I got that far already. the point is i don't want a hardcoded prefix. i want to choose a prefix in the view. It seems i cant unless i also save that prefix in the model, which i would like to avoid, if possible.Maltose
simply add a form field to the form or formset?Homeric
M
0

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 = ''
Maltose answered 5/8, 2012 at 7:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.