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?

vinay kumar
  • 1,451
  • 13
  • 33
mobiletim
  • 303
  • 3
  • 15
  • possible duplicate of [Dynamic File Path in Django](http://stackoverflow.com/questions/5135556/dynamic-file-path-in-django) – dani herrera Aug 03 '12 at 13:12
  • 1
    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. – mobiletim Aug 03 '12 at 13:26

4 Answers4

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()
Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
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.

cutteeth
  • 2,148
  • 3
  • 25
  • 45
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)
Hedde van der Heide
  • 21,841
  • 13
  • 71
  • 100
  • 1
    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. – mobiletim Aug 03 '12 at 13:25
  • simply add a form field to the form or formset? – Hedde van der Heide Aug 03 '12 at 13:30
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 = ''
mobiletim
  • 303
  • 3
  • 15