Using Raja Simon's answer, there is recipe to process all FileField
in the model
class MyModel(models.Model):
file_field = models.FileField(upload_to=upload_to, blank=True, null=True)
def save(self, *args, **kwargs):
if self.id is None:
saved = []
for f in self.__class__._meta.get_fields():
if isinstance(f, models.FileField):
saved.append((f.name, getattr(self, f.name)))
setattr(self, f.name, None)
super(self.__class__, self).save(*args, **kwargs)
for name, val in saved:
setattr(self, name, val)
super(self.__class__, self).save(*args, **kwargs)
Moreover, we can make file location dynamic, i.e. based not only on self.id, but also on id of foreign key or whatever. Just iterate over fields and check if path changed.
def upload_to(o, fn):
if o.parent and o.parent.id:
return parent_upload_to(o.parent, fn)
return "my_temp_dir/{}/{}".format(o.id, fn)
class MyModel(models.Model):
parent = models.ForeignKey(Parent)
def save(self, *args, **kwargs):
# .... code from save() above here
for f in [f for f in self.__class__._meta.get_fields() if isinstance(f, models.FileField)]:
upload_to = f.upload_to
f = getattr(self, f.name) # f is FileField now
if f and callable(upload_to):
_, fn = os.path.split(f.name)
old_name = os.path.normpath(f.name)
new_name = os.path.normpath(upload_to(self, fn))
if old_name != new_name:
old_path = os.path.join(settings.MEDIA_ROOT, old_name)
new_path = os.path.join(settings.MEDIA_ROOT, new_name)
new_dir, _ = os.path.split(new_path)
if not os.path.exists(new_dir):
print "Making dir {}", new_dir
os.makedirs(new_dir)
print "Moving {} to {}".format(old_path, new_path)
try:
os.rename(old_path, new_path)
f.name = new_name
except WindowsError as e:
print "Can not move file, WindowsError: {}".format(e)
super(self.__class__, self).save(*args, **kwargs)