【问题标题】:Django: Uploaded file locked. Can't renameDjango:上传的文件被锁定。无法重命名
【发布时间】:2009-03-12 02:14:52
【问题描述】:

我正在尝试在模型的保存方法中上传文件后重命名文件。我将文件重命名为文件主键和文件标题的组合。

当第一次上传文件、上传新文件以及文件或文件标题没有更改时,我都可以使用它。

但是,当文件的标题被更改,并且系统尝试将旧文件重命名为新路径时,我收到以下错误:

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()

我想问题是,有没有人知道当上传的文件没有被重新上传时如何重命名上传的文件?那是它似乎被锁定/使用中的唯一一次。


更新:

Tyler 的方法是有效的,除非上传新文件时主键不可用并且他的以下技术会引发错误。

if not instance.pk:
    instance.save()

错误:

maximum recursion depth exceeded while calling a Python object

有什么方法可以获取主键吗?

【问题讨论】:

  • 我其实在想为什么 FileField 上没有移动/重命名功能。

标签: python django file-io


【解决方案1】:

我认为您应该更仔细地查看 upload_to 字段。这可能比在保存期间重命名更简单。

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

这也可能是一个可调用对象,例如 函数,它将被调用 获取上传路径,包括 文件名。这个可调用对象必须能够 接受两个参数,并返回一个 Unix 风格的路径(带正斜杠) 被传递到存储 系统。这两个论点将是 通过的是:

【讨论】:

  • 但这不是只有在文件实际上传时才使用的可调用函数吗?如果是这样,仅在保存模型实例时指定它不足以重命名现有文件。
  • 我相信 Guðmundur 是正确的。如果使用了 upload_to 字段并更新了文件的标题,则文件最终不会以新标题重命名。
  • 我的观点是,事后重命名并没有得到很好的支持。在此过程的早期重命名得到了很好的支持。也许重新考虑解决方案以更好地适应 Django 开箱即用的功能会有所帮助。
  • 检查一下 Ty:djangosnippets.org/snippets/1129 一个模型,它在保存后重命名文件以将 PK 值作为名称。
  • 在尝试包含名称之前,我将文件命名为主键。它工作得很好,因为 PK 永远不会改变,文件也永远不必重命名。如果我不能使用另一个字段的值,我可能会回到那个路线。我只是想让文件名更有意义。
【解决方案2】:

我的其他答案已弃用,请改用:

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)。

【讨论】:

  • 这很好用,但是 instance.save() 会抛出此错误:“instancecheck 中超出了最大递归深度”。你知道那是什么意思吗?
  • 如果文件名(或在本例中为 name_slug)更改并且文件未重新上传,则文件名不会更改。没什么大不了的,但这就是我想要的。这仍然比我以前的做法更干净。你知道如何解决这个错误吗?
  • 另外,如果“get_filename”被定义在 File 类之外,我只能让它工作。
【解决方案3】:

上传后,内存中只有一个图像对象,对吧?

您可以自己将此对象保存在您选择的文件夹中,然后手动编辑数据库条目。

你会绕过整个 Django ORM,除非我找不到更多的 Django 方式,否则我不会这样做。

【讨论】:

  • 我不太清楚你的意思。
  • 我只是修改了整个答案以使其更清晰。希望对您有所帮助。
猜你喜欢
  • 1970-01-01
  • 2018-07-24
  • 2014-10-28
  • 1970-01-01
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
  • 2022-08-23
  • 1970-01-01
相关资源
最近更新 更多