Hello! There is a model with FileField and ImageField fields, and a field

user = models.ForeignKey(User) 

It is necessary that the upload_to is formed from the user id (and preferably still from an arbitrary string, but this is not necessary).

For example:

1) option:

"321 / userfile.png"

"321 / doc1.txt"

Option 2:

"321 / avatars / userfile.png"

"321 / documents / doc1.txt"

I tried to transfer to the upload_to function:

 def make_upload_path(self, filename): return str(self.user.id) 

But this only works if I define this function before all the fields, and I cannot define different paths for different fields (as in the second example).

How can this behavior be implemented?

    2 answers 2

    First, if you send some callable to upload_to, it doesn’t have to be a model method at all, I usually use separate functions (the first argument is the object, and self is called this argument or instance is not so important. Then the problem is with need to stick the method in front of the fields of the model disappears.

    Secondly, metaprogramming taxis. The function for transfer to upload_to can not be set explicitly, but generated by another function, approximately the same way as decorators work. It turns out something like:

     def get_upload_to(prefix): def _tmp(instance, filename): return os.path.join(instance.pk, prefix, filename) return _tmp avatar = models.FileField(upload_to=get_upload_to('avatars')) 
    • Thank! I took the function out of the model class, replaced instance.pk with instance.user_id and everything works as it should. - iterq

    There is a solution, like your make_upload_path, you use the function

     def get_file_path(obj, filename): if hasattr(obj, 'upload_dir'): extension = filename.split('.')[-1] filename = "%s.%s" % (uuid.uuid4(), extension) return os.path.join(obj.upload_dir, filename) else: raise AttributeError("%s does not have 'upload_dir' attribute" % obj.__class__.__name__) 

    and in each model, in turn, you prescribe a type property:

      @property def upload_dir(self): return "product_pictures" 

    Thus, you will have unique file names and for each model its own directory where the files will be added. Well, if you need to modify a bit there the fourth line so that the user id gets into the name. And to get a unique path for each field within the same model, duplicate the function or link to the file extension and conditionally expand the path, for example.

    • I understand your decision, but it does not quite fit me. Thanks for the answer. - iterq