简体   繁体   English

django FileSystemStorage的动态路径

[英]Dynamic path for django FileSystemStorage

I was trying to save some files using Django FileSystemStorage. 我试图使用Django FileSystemStorage保存一些文件。 My model is as shown below 我的模型如下所示

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)

But when I save an object of this model only the file name is stored in the db. 但是当我保存此模型的对象时,只有文件名存储在db中。

So when I try to access the path it returns path appended with todays date and not as the uploaded date. 因此,当我尝试访问路径时,它返回附加了今天日期的路径,而不是上传日期。 ie. 即。 If I upload a file on say 09-21-2015 and I try to access the path on the next day it will return account/files/09-22-2015/<file_name> which will be an invalid path. 如果我在09-21-2015上传文件并且我尝试在第二天访问路径它将返回account/files/09-22-2015/<file_name> ,这将是无效路径。 So what tweak should be made to store absolute path in db. 那么应该做什么调整来存储db中的绝对路径。 Or what am I doing wrong here? 或者我在这里做错了什么?

I'm pretty sure, your version does not do what you intend it to: 我很确定,你的版本不符合你的意图:

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

is evaluated when the module is loaded (usually only when you start your application). 在加载模块时评估(通常仅在您启动应用程序时)。 After that the date stays fixed as long as the module is not re-loaded. 之后,只要未重新加载模块,日期就会保持固定。 Hence it points to a directory with the name of the date the application was started, which is probably not what you want. 因此,它指向一个目录,其中包含应用程序启动日期的名称,这可能不是您想要的。

Also, FileSystemStorage serializes with full path name, meaning that this also triggers a migration every other day (because the storage path changed). 此外, FileSystemStorage使用完整路径名序列化,这意味着这也会每隔一天触发一次迁移(因为存储路径已更改)。

You can solve this problem by using a combination of FileSystemStorage (to store files outside of the media directory) and upload_to with a callable: 您可以通过使用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)

This uses a new FileSystemStorage for the base directory of uploaded files and upload_to to determine the name of an uploaded file relative to the storage's root. 这将使用新的FileSystemStorage作为上载文件的基本目录,使用upload_to来确定相对于存储根目录的上载文件的名称。

Edit 1 : Thanks for pointing out that upload_to takes a date format. 编辑1 :感谢您指出upload_to采用日期格式。

Since upload_to also takes strftime() format specifiers, a pure-date related path choice can also be implemented without the callable: 由于upload_to也采用strftime()格式说明符,因此也可以在没有可调用的情况下实现与纯数据相关的路径选择:

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

As for explanation: 至于解释:

A storage is essentially an abstraction of a hierarchical file system in django. 存储本质上是django中分层文件系统的抽象。 FileField s always store their files in a storage . FileField始终将其文件存储存储中 By default the media storage is used, but that can be changed. 默认情况下,使用媒体存储 ,但可以更改。

To determine the path a file is uploaded to, FileField roughly does the following 要确定文件上载的路径, FileField大致执行以下操作

  1. Retrieve the request path , which is the path the file was uploaded with. 检索请求路径 ,该路径是文件上载的路径。
  2. Check if the upload_to option specified for the file field. 检查是否为文件字段指定了upload_to选项。 If upload_to is a string, use this string as a base directory. 如果upload_to是字符串,请将此字符串用作基目录。 upload_to is run through strftime() to process any date specifiers. upload_to通过strftime()运行以处理任何日期说明符。 Concatenate upload_to and the request path, which results in a target path relative to the storage. 连接upload_to和请求路径,这将导致相对于存储的目标路径。
  3. If upload_to is a callable, call it with (instance, request_path) and use the return value as the target path (relative to the storage). 如果upload_to是可调用的,则使用(instance, request_path)调用它,并使用返回值作为目标路径(相对于存储)。
  4. Check if the file already exists within the storage. 检查文件是否已存在于存储中。 If so, derive a new, unique path. 如果是这样,则获得一条新的,独特的路径。
  5. Save file to the storage with the target path. 使用目标路径将文件保存到存储。
  6. Store the target path (still relative to storage) inside the database. 将目标路径(仍然相对于存储)存储在数据库中。

As one can see, the storage is meant to be more or less static. 可以看出,存储意味着或多或少是静态的。 Changing the storage potentially invalidates all existing file paths in the database, because they are relative to the storage. 更改存储可能会使数据库中的所有现有文件路径无效,因为它们与存储相关。

Solved the same problem. 解决了同样的问题。 It uploads the file from the local machine to server 它将文件从本地计算机上载到服务器
views.py

def receiveAudioRecord(request):

    if not os.path.exists('recording/wavFiles'):
        os.makedirs('recording/wavFiles')

    if not request.FILES['fileupload']:
        return render(request, "recording.html", {'msg': "Try Again! Unable to upload. </span>"})

    elif request.method == 'POST' and request.FILES['fileupload']:
        myfile = request.FILES['fileupload']
        fs = FileSystemStorage("recording/wavFiles")
        filename = fs.save(myfile.name, myfile)  # saves the file to `media` folder
        fs.url(filename)  # gets the url

        return render(request, "recording.html",{'msg':"successfully uploaded"})
    else:
        return render(request,"recording.html",{'msg':"Try Again! Unable to upload. </span>"})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM