django FileSystemStorage 的动态路径

mid*_*hun 1 python django django-models filefield

我试图使用 Django FileSystemStorage 保存一些文件。我的模型如下图

key_store = FileSystemStorage(
location='account/files/'+datetime.date.today().isoformat())


class Account(models.Model):
    name = models.CharField(max_length=100, null=True, blank=True)
    user = models.ForeignKey(User, related_name='auth_user_account_relation')
    subscription_id = models.CharField(max_length=100, null=True, blank=True)
    info_file = models.FileField(storage=key_store)
Run Code Online (Sandbox Code Playgroud)

但是当我保存这个模型的对象时,只有文件名存储在数据库中。

因此,当我尝试访问路径时,它返回附加了今天日期的路径,而不是作为上传日期。IE。如果我在 2015 年 9 月 21 日上传文件并尝试在第二天访问该路径,它将返回 account/files/09-22-2015/<file_name>无效路径。那么应该进行什么调整来在db中存储绝对路径。或者我在这里做错了什么?

dhk*_*hke 8

我很确定,您的版本不符合您的意图:

key_store = FileSystemStorage(
    location='account/files/'+datetime.date.today().isoformat()
)
Run Code Online (Sandbox Code Playgroud)

在加载模块时评估(通常仅在您启动应用程序时)。之后,只要不重新加载模块,日期就会保持固定。因此它指向一个带有应用程序启动日期名称的目录,这可能不是您想要的。

此外,FileSystemStorage使用完整路径名进行序列化,这意味着这也会每隔一天触发一次迁移(因为存储路径已更改)。

您可以通过使用FileSystemStorage(将文件存储在媒体目录之外)和upload_to可调用的组合来解决此问题:

key_store = FileSystemStorage(location='account/files/')

def key_store_upload_to(instance, path):
    # prepend date to path
    return os.path.join(
        datetime.date.today().isoformat(), 
        path
    )

class Account(models.Model):
    # [...]
    info_file = models.FileField(storage=key_store, upload_to=key_store_upload_to)
Run Code Online (Sandbox Code Playgroud)

这使用 newFileSystemStorage作为上传文件的基本目录,并upload_to确定上传文件相对于存储根目录的名称。

编辑 1:感谢您指出upload_to采用日期格式。

由于upload_to也采用strftime()格式说明符,因此也可以在没有可调用文件的情况下实现与纯日期相关的路径选择:

info_file = models.FileField(storage=key_store, upload_to='account/files/%Y-%m-%d')
Run Code Online (Sandbox Code Playgroud)

至于解释:

一个存储本质上是在Django分层文件系统的抽象。FileFields 总是将他们的文件存储在一个storage 中。默认情况下使用媒体存储,但可以更改。

判断一个文件上传到的路径,FileField大致做如下

  1. 检索请求路径,这是文件上传的路径。
  2. 检查是否upload_to为文件字段指定了选项。如果upload_to是字符串,则将此字符串用作基本目录。upload_to运行strftime()以处理任何日期说明符。连接upload_to和请求路径,从而产生相对于存储的目标路径。
  3. 如果upload_to是可调用的,则调用它(instance, request_path)并使用返回值作为目标路径(相对于存储)。
  4. 检查文件是否已存在于存储中。如果是这样,请推导出一条新的、唯一的路径。
  5. 使用目标路径将文件保存到存储中。
  6. 将目标路径(仍然相对于存储)存储在数据库中。

可以看出,存储或多或少是静态的。更改存储可能会使数据库中的所有现有文件路径无效,因为它们与存储相关。