Hello, In django before version 1.4, there was an option in the model for models. FileField to specify "dynamically" the created path to store files in the upload_to variable

models.py #... attach = models.FileField(verbose_name=u'Приложение', blank=True, upload_to=lambda instance, filename: 'attach/%s/%s' % (instance.id,filename)) 

D django version 1.4 seems to be assigned an id later and therefore instance.id = None and also instance.pk = None. Tell me how you can specify the model id in the path.

    3 answers 3

    Your question is a little confusing, because personally in my version to 1.4, id was also not available in upload_to .

    In general, the issue of storing file paths is quite beaten. For me, the most normal option is to build a hash from timestamp + file name and create directories for the first 4 characters of the hash

     upload_to = 'upload_path/%s/%s/%s.jpg' % (hash[:1], hash[2:3], hash) 

    UPDATE Regarding exactly the id in the file name. You need after saving the file, i.e. after assigning an id in the database, generate a new path and accordingly move the file along the new path. In my subjective opinion, the operation is too expensive.

    UPDATE2

     import uuid def get_file_path(instance, filename): ext = filename.split('.')[-1] filename = "%s.%s" % (uuid.uuid4(), ext) return 'uploads/%s/%s/%s.jpg' % (filename[:1], filename[2:3], filename) 

    and in the model

     file = models.FileField(upload_to=get_file_path, null=True, blank=True, verbose_name=_(u'Contact list')) 
    • You mean so? attach = models.FileField (verbose_name = u'Application ', blank = True, upload_to =' attach /% Y /% m /% d ') - Kotyamba
    • one
      I mean upload_to accepts a callable object, i.e. it may be a function. See the answer in the example. - ChehoV

    According to the documentation for versions up to 1.4 inclusive :

    It is not necessary to make sure that it can be used for the primary key field.

    Accordingly, this behavior was before, maybe you made a mistake.

    Yes, you can make a dirty hack to solve this problem by trapping the signal of saving the model and moving the file along a new path ... if you need it - you have to decide it yourself.


    Or, since the documentation says about AutoField , try replacing the id field of the model with something different (hash from the file? UUID? Solve it yourself). Maybe this trick will work.

    • I agree, I was wrong, I just checked the previous project in which the id is saved because the element was created earlier, and the file is written later. - Kotyamba
    • Solved the issue, did this: attach = models.FileField (verbose_name = u'Application ', blank = True, upload_to = lambda instance, filename:' attach /% (id) s /% (dt) s /% (filename) s '% {' id ': instance.author.id,' filename ': filename,' dt ': datetime.date.today ()}) - Kotyamba

    The ID will be only after the row is inserted, and the row is inserted only after all the fields have been recorded. Therefore, you cannot know the ID until the object is saved. The simplest thing is to save in the transaction with attach=None , then update the field and re-save. Something like that:

     with transaction.commit_on_success(): file = File(..., attach=None) file.save() file.attach = attachment file.save() 

    As part of the optimization, you can prefetch an ID, but this is not a very nice and vendor-specific solution that is difficult to transfer between databases. But it eliminates a pair of INSERT + UPDATE, limited to one insert. For PostgreSQL, which can SEQUENCEs, for example, there will be something in the spirit:

     from django.db import connection assert connection.vendor == "postgresql" cursor = connection.cursor() cursor.execute("SELECT nextval('seq_files_id')") new_id, = cursor.fetchone() file = File(id=new_id, ...) file.save()