2009-03-12 5 views
3

Я пытаюсь переименовать файл после его загрузки в метод сохранения модели. Я переименовываю файл в комбинацию первичного ключа файлов и пули названия файла.Django: Загруженный файл заблокирован. Невозможно переименовать

У меня есть работа, когда файл загружается первым, когда загружается новый файл и когда нет изменений в названии файла или файла.

Однако, когда название файла изменяется, и система пытается переименовать старый файл на новый путь, я получаю следующее сообщение об ошибке:

WindowsError at /admin/main/file/1/ 
(32, 'The process cannot access the file because it is being used by another process') 

Я действительно не знаю, как получить вокруг этого. Я пробовал просто копировать файл на новый путь. Это работает, но я не знаю, что могу удалить старую версию.

Укороченная Модель:

class File(models.Model): 
    nzb = models.FileField(upload_to='files/') 
    name = models.CharField(max_length=256) 
    name_slug = models.CharField(max_length=256, blank=True, null=True, editable=False) 

    def save(self): 
     # Create the name slug. 
     self.name_slug = re.sub('[^a-zA-Z0-9]', '-', self.name).strip('-').lower() 
     self.name_slug = re.sub('[-]+', '-', self.name_slug) 

     # Need the primary key for naming the file. 
     super(File, self).save() 

     # Create the system paths we need. 
     orignal_nzb = u'%(1)s%(2)s' % {'1': settings.MEDIA_ROOT, '2': self.nzb} 
     renamed_nzb = u'%(1)sfiles/%(2)s_%(3)s.nzb' % {'1': settings.MEDIA_ROOT, '2': self.pk, '3': self.name_slug} 

     # Rename the file. 
     if orignal_nzb not in renamed_nzb: 
      if os.path.isfile(renamed_nzb): 
       os.remove(renamed_nzb) 

      # Fails when name is updated. 
      os.rename(orignal_nzb, renamed_nzb) 

     self.nzb = 'files/%(1)s_%(2)s.nzb' % {'1': self.pk, '2': self.name_slug} 

     super(File, self).save() 

Я полагаю, что вопрос, кто-нибудь знает, как я могу переименовать загруженный файл, если загруженный файл не может быть повторно загружен? Это единственный раз, когда кажется, что он заблокирован/используется.


Update: подход

Тайлер работает, за исключением того, когда новый файл загружен первичный ключ не доступен, и его метод ниже бросает ошибку.

if not instance.pk: 
    instance.save() 

Ошибка:

maximum recursion depth exceeded while calling a Python object 

Есть ли способ, чтобы захватить первичный ключ?

+0

Я действительно задавался вопросом, почему на FileField нет функции move/rename. – Powerlord

ответ

5

Я думаю, вам следует более внимательно изучить поле upload_to. Это, вероятно, будет проще, чем возиться с переименованием во время сохранения.

http://docs.djangoproject.com/en/dev/ref/models/fields/#filefield

This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename. This callable must be able to accept two arguments, and return a Unix-style path (with forward slashes) to be passed along to the storage system. The two arguments that will be passed are:

+0

Но разве это нельзя использовать только когда файл загружен? Если это так, указывать его недостаточно, чтобы переименовать существующий файл, когда экземпляр модели будет сохранен. –

+0

Я верю, что Гудмундур верен. Если поле upload_to было использовано и название файла было обновлено, файл не будет переименован в новый заголовок. –

+0

Моя точка зрения заключается в том, что переименование после факта не поддерживается. Переименование в начале процесса хорошо поддерживается. Возможно, было бы полезно переосмыслить решение, чтобы лучше соответствовать тому, что делает Django. –

0

После загрузки, все у вас есть объект, образ в памяти, не так ли?

Вы можете сохранить этот объект самостоятельно в выбранной вами папке, а затем вручную отредактировать запись базы данных.

Вы бы обошли весь Django ORM, и это не то, что я сделал бы, если бы я не смог найти более удобный способ Django.

+0

Я не совсем уверен, что вы подразумеваете под этим. –

+0

Я просто изменил весь ответ, чтобы сделать его более ясным. Надеюсь, поможет. – voyager

3

Мой другой ответ устарел, используйте вместо этого:

class File(models.Model): 
    nzb = models.FileField(upload_to=get_filename) 
    ... 
    def get_filename(instance, filename): 
     if not instance.pk: 
      instance.save() 
     # Create the name slug. 
     name_slug = re.sub('[^a-zA-Z0-9]', '-', instance.name).strip('-').lower() 
     name_slug = re.sub('[-]+', '-', name_slug) 

     filename = u'filess/%(2)s_%(3)s.nzb' % {'2': instance.pk, '3': name_slug} 

     return filename 

В 1,0, upload_to can be callable, в этом случае он должен вернуть имя файла, включая путь (по отношению к MEDIA_ROOT).

+0

Это работает очень хорошо, однако instance.save() выдает эту ошибку: «максимальная глубина рекурсии превышена в __instancecheck__». Вы знаете, что это значит? –

+0

Если имя файла (или в этом случае name_slug) изменяется и файл не загружается повторно, имя файла не изменяется. Не очень, но это то, за что я стрелял. Это все еще будет чище, чем я это делал раньше. Вы знаете, как исправить эту ошибку? –

+0

Кроме того, я мог бы заставить его работать только в том случае, если «get_filename» не выполнялось за пределами класса File и над ним. –

Смежные вопросы