Django 1.8 文件管理

题记

本文为学习 Django 文档同步翻译,原文地址:https://docs.djangoproject.com/en/1.8/topics/files/


文件管理

下面讨论 Django 里面关于用户上传的文件的管理。有些足够底层的 API 足以让我们完全随心所欲地处理文件。如果需要考虑关于“静态文件”(意为非用户上传的只读静态文件),则另行参考此文档:<https://docs.djangoproject.com/en/1.8/howto/static-files

默认情况下,Django 本地存储(上传的)文件,通过 MEDIA_ROOTMEDIA_URL 设置来实现。下面的例子假设你已经使用这些默认值。

插播一下,开发过程中可以通过 https://docs.djangoproject.com/en/1.8/howto/static-files/#serving-uploaded-files-in-development 这个方式来伺服静态文件以及上传的文件。

举个例子:

# settings.py

MEDIA_ROOT = os.path.abspath('../media')
MEDIA_URL = '/media/'

# urls.py

from django.conf.urls.static import static

urlpatterns = [
    # ...
] + static(
    settings.MEDIA_URL,
    document_root=settings.MEDIA_ROOT,
)

然而,Django 提供了一些方式以允许你完全定制 Django 存储文件的场合以及方法,本文的第二部分就会为你讲述这些存储系统是如何工作的。


在模型中使用文件

只要在模型中使用 FileField 或者 ImageField,Django 就会提供文件处理的 API。

from django.db import models

class Car(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    photo = models.ImageField(upload_to='cars')

于是,起码在 admin 后台就可以上传并编辑管理这个图片字段了。upload_to 的参数指明上传的图片将存放在相对于 settings.MEDIA_ROOT 的相对路径。

>>> car = Car.objects.get(name="57 Chevy")
>>> car.photo
<ImageFieldFile: chevy.jpg>
>>> car.photo.name
'cars/chevy.jpg'
>>> car.photo.path
'/media/cars/chevy.jpg'
>>> car.photo.url
'http://media.example.com/cars/chevy.jpg'

如上,调用模型可以获取这个附件的各种信息,通过这个字段获取模型对象的字段时,将得到一个 File 对象,即具备所有我们下面讲的 File 的所有接口。


File 对象

Django 内部总是用 File 对象来封装并表示文件,这是在 Python 原生 file 对象上的一个轻量封装。

绝大多数时候,你都只会使用 django 给你的 File 对象(即例如上面的获取一个模型对象的文件字段。)

如果真要自己搞一个,最简单的办法就是通过 Python 原生 File 对象自己创建一个:

>>> from django.core.files import File

# Create a Python file object using open()
>>> f = open('/tmp/hello.world', 'w')
>>> myfile = File(f)

然后这样的话就可以使用 File 对象的所有接口了。

注意这样创建出来 File 文件后,打开的文件不会自动关闭,下面的方式就可以:

>>> from django.core.files import File

# Create a Python file object using open() and the with statement
>>> with open('/tmp/hello.world', 'w') as f:
...     myfile = File(f)
...     myfile.write('Hello World')
...
>>> myfile.closed
True
>>> f.closed
True

当遍历很多文件对象的时候,正确关闭文件尤其重要,如果用完不关,就会有这类风险:

IOError: [Errno 24] Too many open files

文件存储

荧幕后面,Django 代理了关于文件存储到哪里的决定,然后用起来就像我们理解的一般其他文件打开关闭、读写等等一样(但是后面可能不一定是存放在操作系统的文件系统中的,只是接口统一了)。

Django 的默认文件存储是通过 DEFAULT_FILE_STORAGE 的 settings 配置决定的,如果不额外显式指定存储系统(在调用的时候),我们默认就会用这个。

看看下面的默认的原生文件存储系统,如果想自己写一个,参考:https://docs.djangoproject.com/en/1.8/howto/custom-file-storage/

storage 存储对象

尽管很多时候你想用一个(被 Django 代理的)File 对象,但也可以直接使用文件的存储。你可以创建一个自定义存储类的实例,或者更有用的,创建一个全局的默认存储系统。

>>> from django.core.files.storage import default_storage
>>> from django.core.files.base import ContentFile

>>> path = default_storage.save('/path/to/file', ContentFile('new content'))
>>> path
'/path/to/file'

>>> default_storage.size(path)
11
>>> default_storage.open(path).read()
'new content'

>>> default_storage.delete(path)
>>> default_storage.exists(path)
False

原生文件系统 storage 类

Django 封装了 django.core.files.storage.FileSystemStorage 类,这个类实现了基本的本地存储方式。

例如,下面的代码会将上传的文件放到 /media/photos 下面,而不管你的 MEDIA_ROOT 设成什么。

from django.db import models
from django.core.files.storage import FileSystemStorage

fs = FileSystemStorage(location='/media/photos')

class Car(models.Model):
    ...
    photo = models.ImageField(storage=fs)

自定义存储系统 也按照同样的方式运作,你可以在 models.FileField 定义的时候作为 storage 参数来制定它们。


【转载请附】愿以此功德,回向 >>

原文链接:https://www.huangwenchao.com.cn/2015/09/django-1-8-manage-files.html【Django 1.8 文件管理】

发表评论

电子邮件地址不会被公开。 必填项已用*标注