管理檔案¶
本文件描述 Django 用於處理使用者上傳等檔案的檔案存取 API。較低層級的 API 具有足夠的通用性,您可以將它們用於其他目的。如果您想要處理「靜態檔案」(JS、CSS 等),請參閱如何管理靜態檔案 (例如圖片、JavaScript、CSS)。
預設情況下,Django 會在本機儲存檔案,並使用 MEDIA_ROOT
和 MEDIA_URL
設定。以下範例假設您正在使用這些預設值。
但是,Django 提供了編寫自訂檔案儲存系統的方法,讓您可以完全自訂 Django 儲存檔案的位置和方式。本文檔的後半部分描述這些儲存系統如何運作。
在模型中使用檔案¶
當您使用 FileField
或 ImageField
時,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
的非圖片資料屬性 (例如 height
、width
和 size
) 可在實例上使用,但若不重新開啟圖片,則無法使用底層圖片資料。例如
>>> 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)
使用可呼叫物件¶
您可以將可呼叫物件作為 storage
參數,用於 FileField
或 ImageField
。這可讓您在執行階段修改所使用的儲存,例如,為不同的環境選擇不同的儲存。
當載入您的模型類別時,將會評估您的可呼叫物件,且必須傳回 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)