管理文件

这个文档描述 Django 文件访问用于文件的 API,例如用户上传的文件。较底层的API足够通用,你可以为其他目的来使用它们。如果你想处理 “static files” (JS, CSS, etc.),可以查看 如何管理静态文件(如图片、JavaScript、CSS)

默认情况下,Django 使用 MEDIA_ROOTMEDIA_URL 设置本地存储。下面的例子假设你在使用这些默认设置。

不过,Django 提供编写自定义 file storage systems 的方法,允许你完全自定义 Django 存储文件的位置和方式。这篇文档的后半部分描述了存储系统的工作方式。

在模型中使用文件

当你使用 FileFieldImageField 时,Django 提供了一组处理文件的API。

考虑下面的模型,使用 ImageField 来存储照片:

  1. from django.db import models
  2. class Car(models.Model):
  3. name = models.CharField(max_length=255)
  4. price = models.DecimalField(max_digits=5, decimal_places=2)
  5. photo = models.ImageField(upload_to="cars")
  6. specs = models.FileField(upload_to="specs")

任何 Car 实例都将有一个 photo 属性,您可以使用它来获取附加照片的详细信息:

  1. >>> car = Car.objects.get(name="57 Chevy")
  2. >>> car.photo
  3. <ImageFieldFile: cars/chevy.jpg>
  4. >>> car.photo.name
  5. 'cars/chevy.jpg'
  6. >>> car.photo.path
  7. '/media/cars/chevy.jpg'
  8. >>> car.photo.url
  9. 'https://media.example.com/cars/chevy.jpg'

car.photo 是一个 File 对象,这意味着它拥有下面所描述的所有方法和属性。

备注

文件在数据库中作为保存模型的一部分,因此在模型被保存之前,不能依赖磁盘上使用的实际文件名。

例如,您可以通过将文件的 name 设置为相对于文件存储位置的路径(如果使用默认的 FileSystemStorage,则为 MEDIA_ROOT)来更改文件名:

  1. >>> import os
  2. >>> from django.conf import settings
  3. >>> initial_path = car.photo.path
  4. >>> car.photo.name = "cars/chevy_ii.jpg"
  5. >>> new_path = settings.MEDIA_ROOT + car.photo.name
  6. >>> # Move the file on the filesystem
  7. >>> os.rename(initial_path, new_path)
  8. >>> car.save()
  9. >>> car.photo.path
  10. '/media/cars/chevy_ii.jpg'
  11. >>> car.photo.path == new_path
  12. True

将磁盘上的现有文件保存到 FileField

  1. >>> from pathlib import Path
  2. >>> from django.core.files import File
  3. >>> path = Path("/some/external/specs.pdf")
  4. >>> car = Car.objects.get(name="57 Chevy")
  5. >>> with path.open(mode="rb") as f:
  6. ... car.specs = File(f, name=path.name)
  7. ... car.save()
  8. ...

备注

虽然 ImageField 的非图像数据属性,如 heightwidthsize 可以在实例上使用,但底层图像数据不能在不重新打开图像的情况下使用。例如:

  1. >>> from PIL import Image
  2. >>> car = Car.objects.get(name="57 Chevy")
  3. >>> car.photo.width
  4. 191
  5. >>> car.photo.height
  6. 287
  7. >>> image = Image.open(car.photo)
  8. # Raises ValueError: seek of closed file.
  9. >>> car.photo.open()
  10. <ImageFieldFile: cars/chevy.jpg>
  11. >>> image = Image.open(car.photo)
  12. >>> image
  13. <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=191x287 at 0x7F99A94E9048>

File 对象

在内部,Django 在任何需要表示文件的时候使用 django.core.files.File

大部分情况下你只需要使用 Django 提供的 File (即附加到上述模型的文件或已经上传的文件)。

如果需要自己构造一个 File,最简单的方法是使用 Python 内置的 file 对象创建一个:

  1. >>> from django.core.files import File
  2. # Create a Python file object using open()
  3. >>> f = open("/path/to/hello.world", "w")
  4. >>> myfile = File(f)

现在你可以使用 File 类的任何属性和方法。

请注意,以这种方式创建的文件不会自动关闭。可以使用以下方法自动关闭文件:

  1. >>> from django.core.files import File
  2. # Create a Python file object using open() and the with statement
  3. >>> with open("/path/to/hello.world", "w") as f:
  4. ... myfile = File(f)
  5. ... myfile.write("Hello World")
  6. ...
  7. >>> myfile.closed
  8. True
  9. >>> f.closed
  10. True

在循环遍历大量对象时访问文件字段时关闭文件尤其重要。如果在访问文件后不手动关闭它们,可能会出现耗尽文件描述符的风险。这可能会导致以下错误:

  1. OSError: [Errno 24] Too many open files

文件存储

在后台,Django将如何以及在哪里存储文件的决策委托给文件存储系统。这个对象实际上理解文件系统、打开和读取文件等。

Django 的默认文件存储是 'django.core.files.storage.FileSystemStorage'。如果您没有在 STORAGES 设置的 default 键中明确提供一个存储系统,那么将使用这个存储系统。

参阅下面内置默认文件存储系统的细节,也可以查看 如何编写一个自定义的文件存储类 来了解编写自己的文件存储系统的信息。

存储对象

虽然大多数情况下,您会希望使用一个 File 对象(它会委托给适当的文件存储),但您也可以直接使用文件存储系统。您可以创建某个自定义文件存储类的实例,或者更常见的做法是使用全局默认的存储系统:

  1. >>> from django.core.files.base import ContentFile
  2. >>> from django.core.files.storage import default_storage
  3. >>> path = default_storage.save("path/to/file", ContentFile(b"new content"))
  4. >>> path
  5. 'path/to/file'
  6. >>> default_storage.size(path)
  7. 11
  8. >>> default_storage.open(path).read()
  9. b'new content'
  10. >>> default_storage.delete(path)
  11. >>> default_storage.exists(path)
  12. False

查看 文件存储 API 来了解文件存储API。

内置文件存储类

Django 附带一个 django.core.files.storage.FileSystemStorage 类,这个类实现基础的本地文件系统文件存储。

例如,下面的代码将存储上传文件到 /media/photos 而会忽略你在 MEDIA_ROOT 的设置:

  1. from django.core.files.storage import FileSystemStorage
  2. from django.db import models
  3. fs = FileSystemStorage(location="/media/photos")
  4. class Car(models.Model):
  5. ...
  6. photo = models.ImageField(storage=fs)

自定义存储系统( Custom storage systems )的工作方式也一样:将它们作为 storage 参数传递给 FileField

使用callable

你可以使用callable作为 FileFieldImageFieldstorage 参数。它允许你在运行时修改存储参数,不同环境选择不同存储,例如。

当模型类被加载时,callable将进行判断,并返回 Storage 实例。

例如:

  1. from django.conf import settings
  2. from django.db import models
  3. from .storages import MyLocalStorage, MyRemoteStorage
  4. def select_storage():
  5. return MyLocalStorage() if settings.DEBUG else MyRemoteStorage()
  6. class MyModel(models.Model):
  7. my_file = models.FileField(storage=select_storage)

要设置在 STORAGES 设置中定义的存储系统,可以使用 storages

  1. from django.core.files.storage import storages
  2. def select_storage():
  3. return storages["mystorage"]
  4. class MyModel(models.Model):
  5. upload = models.FileField(storage=select_storage)