Reputation: 333
I'm trying to build a path for a FileField, getting and using the instance to get another data for the URL, plus the field name, to get something like:
/media/documents/<instance_data>/<field_name>.pdf
My best working approach is:
class UserDocFileField(models.FileField):
def get_fixed_folder_path(self, instance, filename):
return 'documents/{}/{}.pdf'.format(instance.user.rfc, self.name)
def __init__(self, *args, **kwargs):
kwargs["upload_to"] = self.get_fixed_folder_path
super(UserDocFileField, self).__init__(*args, **kwargs)
And in my model:
class Documents(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
file_1 = UserDocFileField()
file_2 = UserDocFileField()
# ... other documents
Giving me what I'm looking for, i.e.:
/media/documents/ABCD840422ABC/file_1.pdf
However, this makes Django to generate a migration file every single time I run makemigrations, I have tried to set it as an inner class, rewriting the super as
super(Documents.UserDocFileField, self).__init__(*args, **kwargs)
But, I got this error:
NameError: name 'Documents' is not defined
So, is there a way to avoid the generations of migrations files or a better approach to solve this?
Upvotes: 1
Views: 2274
Reputation: 1
For solve my question and create a folder based in user I use this method:
import os, uuid
def get_upload_path(instance, filename):
'''Split the name of ext, create a new name with uuid and return the path'''
ext = '.' + filename.split('.')[1]
filename = f"{uuid.uuid1()}" + ext
upload_path = os.path.join('images', 'user', str(instance.user.pk), filename)
return upload_path
Upvotes: 0
Reputation: 599698
One way of doing this is to use a custom class for the upload_to
itself, with a __call__
method to make the instance callable. In order to make that serializable for migrations you then need to add a deconstruct
method. So:
class UploadTo:
def __init__(self, name):
self.name = name
def __call__(self, instance, filename):
return 'documents/{}/{}.pdf'.format(instance.user.rfc, self.name)
def deconstruct(self):
return ('myapp.models.UploadTo', [self.name], {})
class Documents(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
file_1 = FileField(upload_to=UploadTo('file_1'))
file_2 = FileField(upload_to=UploadTo('file_2'))
Honestly though, at this point I'd probably just write separate upload_to
functions for each field.
Upvotes: 6