ファイルの管理¶
この文書では、ユーザがアップロードしたようなファイルに対する Django のファイルアクセス API について説明します。下位レベルの API は十分一般的なので、他の目的にも使えます。"静的ファイル" (JS や CSS など) を扱いたい場合は、 静的ファイル (画像、JavaScript、CSS など) を管理する を参照してください。
デフォルトでは、Django は MEDIA_ROOT
と MEDIA_URL
の設定を使って、ファイルをローカルに保存します。以下の例では、これらのデフォルトを使うことを前提にしています。
しかしながら、Djangoは、 Djangoがどこにどうやってファイルを保存するかの複雑なカスタムを許可するファイルストレージシステム file storage systems を提供しています。このドキュメントの後半では、それらのストレージシステムの働きについて説明します。
モデルでファイルを使う¶
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
を作成する必要がある場合、最も簡単な方法は 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)
カスタムのストレージシステム も同じように動作します。 FileField
の storage
引数として渡すことができます。
呼び出し可能オブジェクト (callable) を使う¶
呼び出し可能オブジェクトは FileField
や ImageField
の storage
パラメータとして使用できます。これにより、実行時に使用するストレージを変更し、例えば環境ごとに異なるストレージを選択できます。
呼び出し可能オブジェクトは、モデルクラスが読み込まれたときに評価され、 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)