管理檔案

本文件描述 Django 用於處理使用者上傳等檔案的檔案存取 API。較低層級的 API 具有足夠的通用性,您可以將它們用於其他目的。如果您想要處理「靜態檔案」(JS、CSS 等),請參閱如何管理靜態檔案 (例如圖片、JavaScript、CSS)

預設情況下,Django 會在本機儲存檔案,並使用 MEDIA_ROOTMEDIA_URL 設定。以下範例假設您正在使用這些預設值。

但是,Django 提供了編寫自訂檔案儲存系統的方法,讓您可以完全自訂 Django 儲存檔案的位置和方式。本文檔的後半部分描述這些儲存系統如何運作。

在模型中使用檔案

當您使用 FileFieldImageField 時,Django 會提供一組 API 供您處理該檔案。

考慮以下模型,使用 ImageField 來儲存照片

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")
    specs = models.FileField(upload_to="specs")

任何 Car 實例都會有一個 photo 屬性,您可以使用它來取得附加照片的詳細資訊

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

此物件 – 範例中的 car.photo – 是一個 File 物件,這表示它具有以下描述的所有方法和屬性。

注意

檔案會儲存為在資料庫中儲存模型的一部分,因此在模型儲存後才能確定磁碟上使用的實際檔案名稱。

例如,您可以透過將檔案的 name 設定為相對於檔案儲存位置的路徑(如果您使用預設的 FileSystemStorage,則為 MEDIA_ROOT),來變更檔案名稱

>>> import os
>>> from django.conf import settings
>>> initial_path = car.photo.path
>>> car.photo.name = "cars/chevy_ii.jpg"
>>> new_path = settings.MEDIA_ROOT + car.photo.name
>>> # Move the file on the filesystem
>>> os.rename(initial_path, new_path)
>>> car.save()
>>> car.photo.path
'/media/cars/chevy_ii.jpg'
>>> car.photo.path == new_path
True

若要將磁碟上的現有檔案儲存到 FileField

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

注意

雖然 ImageField 的非圖片資料屬性 (例如 heightwidthsize) 可在實例上使用,但若不重新開啟圖片,則無法使用底層圖片資料。例如

>>> from PIL import Image
>>> car = Car.objects.get(name="57 Chevy")
>>> car.photo.width
191
>>> car.photo.height
287
>>> image = Image.open(car.photo)
# Raises ValueError: seek of closed file.
>>> car.photo.open()
<ImageFieldFile: cars/chevy.jpg>
>>> image = Image.open(car.photo)
>>> image
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=191x287 at 0x7F99A94E9048>

File 物件

在內部,每當需要表示檔案時,Django 都會使用 django.core.files.File 實例。

大多數時候,您會使用 Django 提供給您的 File(即,如上所述附加到模型的檔案,或是上傳的檔案)。

如果您需要自行建構 File,最簡單的方法是使用 Python 內建的 file 物件來建立一個。

>>> from django.core.files import File

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

現在您可以使用 File 類別的任何記載屬性和方法。

請注意,以這種方式建立的檔案不會自動關閉。以下方法可用於自動關閉檔案

>>> from django.core.files import File

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

當在大量物件的迴圈中存取檔案欄位時,關閉檔案尤為重要。如果在存取檔案後未手動關閉檔案,可能會導致檔案描述器耗盡的風險。這可能會導致以下錯誤

OSError: [Errno 24] Too many open files

檔案儲存

在幕後,Django 會將如何和在何處儲存檔案的決策委派給檔案儲存系統。這個物件實際上了解檔案系統、開啟和讀取檔案等。

Django 的預設檔案儲存是 'django.core.files.storage.FileSystemStorage'。如果您沒有在 STORAGES 設定的 default 鍵中明確提供儲存系統,則會使用此儲存系統。

請參閱下文,了解內建預設檔案儲存系統的詳細資訊,並參閱如何編寫自訂儲存類別,以取得編寫您自己的檔案儲存系統的資訊。

儲存物件

雖然大多數時候您會想要使用 File 物件(它會委派給該檔案的適當儲存),但您可以直接使用檔案儲存系統。您可以建立某些自訂檔案儲存類別的實例,或者更常見的是,您可以使用全域預設儲存系統

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

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

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

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

請參閱 檔案儲存 API,以取得檔案儲存 API。

內建檔案系統儲存類別

Django 隨附一個 django.core.files.storage.FileSystemStorage 類別,它實作基本的本機檔案系統檔案儲存。

例如,無論您的 MEDIA_ROOT 設定為何,下列程式碼都會將上傳的檔案儲存在 /media/photos

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

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


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

自訂儲存系統 的運作方式相同:您可以將它們作為 FileFieldstorage 引數傳入。

使用可呼叫物件

您可以將可呼叫物件作為 storage 參數,用於 FileFieldImageField。這可讓您在執行階段修改所使用的儲存,例如,為不同的環境選擇不同的儲存。

當載入您的模型類別時,將會評估您的可呼叫物件,且必須傳回 Storage 的實例。

例如

from django.conf import settings
from django.db import models
from .storages import MyLocalStorage, MyRemoteStorage


def select_storage():
    return MyLocalStorage() if settings.DEBUG else MyRemoteStorage()


class MyModel(models.Model):
    my_file = models.FileField(storage=select_storage)

為了設定在 STORAGES 設定中定義的儲存,您可以使用 storages

from django.core.files.storage import storages


def select_storage():
    return storages["mystorage"]


class MyModel(models.Model):
    upload = models.FileField(storage=select_storage)
返回頂部