ファイルの管理

この文書では、ユーザがアップロードしたようなファイルに対する Django のファイルアクセス API について説明します。下位レベルの API は十分一般的なので、他の目的にも使えます。"静的ファイル" (JS や CSS など) を扱いたい場合は、 静的ファイル (画像、JavaScript、CSS など) を管理する を参照してください。

デフォルトでは、Django は MEDIA_ROOTMEDIA_URL の設定を使って、ファイルをローカルに保存します。以下の例では、これらのデフォルトを使うことを前提にしています。

しかしながら、Djangoは、 Djangoがどこにどうやってファイルを保存するかの複雑なカスタムを許可するファイルストレージシステム file storage systems を提供しています。このドキュメントの後半では、それらのストレージシステムの働きについて説明します。

モデルでファイルを使う

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 のインスタンスでは、 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)

カスタムのストレージシステム も同じように動作します。 FileFieldstorage 引数として渡すことができます。

呼び出し可能オブジェクト (callable) を使う

呼び出し可能オブジェクトは FileFieldImageFieldstorage パラメータとして使用できます。これにより、実行時に使用するストレージを変更し、例えば環境ごとに異なるストレージを選択できます。

呼び出し可能オブジェクトは、モデルクラスが読み込まれたときに評価され、 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)
Back to Top