mobiletim
mobiletim

Reputation: 313

django - set the upload_to in the view

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

Answers (4)

cutteeth
cutteeth

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

mobiletim
mobiletim

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

Chris Pratt
Chris Pratt

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

Hedde van der Heide
Hedde van der Heide

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

Related Questions