Управление файлами¶
Этот документ описывает API доступа к файлам Django для файлов, например, загруженных пользователем. API нижнего уровня достаточно общие, чтобы вы могли использовать их для других целей. Если вы хотите работать со «статическими файлами» (JS, CSS и т.д.), смотрите Как управлять статическими файлами (например, изображениями, JavaScript, CSS).
По умолчанию Django хранит файлы локально, используя параметры MEDIA_ROOT
и MEDIA_URL
. В примерах ниже предполагается, что вы используете эти настройки по умолчанию.
Однако Django предоставляет способы написания пользовательских file storage systems, которые позволяют вам полностью настроить, где и как 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
'http://media.example.com/cars/chevy.jpg'
Этот объект – car.photo
в примере – является объектом File
, что означает, что он имеет все методы и атрибуты, описанные ниже.
Примечание
Файл сохраняется как часть сохранения модели в базе данных, поэтому фактическое имя файла, используемое на диске, не может быть определено до тех пор, пока модель не будет сохранена.
Например, можно изменить имя файла, установив в качестве пути name
путь относительно места расположения файлового хранилища (MEDIA_ROOT
, если используется стандартное FileSystemStorage
):
>>> 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
каждый раз, когда ему нужно представить файл.
В большинстве случаев вы будете использовать 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
'
. Если вы явно не укажете систему хранения в ключе default
настройки STORAGES
, то будет использоваться именно она.
Подробности о встроенной системе хранения файлов по умолчанию смотрите ниже, а информацию о написании собственной системы хранения файлов - в разделе Как написать пользовательский класс хранения.
Объекты хранения¶
Хотя в большинстве случаев необходимо использовать объект 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/photos
независимо от того, какова ваша настройка MEDIA_ROOT
:
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)
Custom storage systems работают одинаково: вы можете передать их в качестве аргумента storage
в FileField
.
Использование вызываемого объекта¶
В качестве параметра storage
для FileField
или ImageField
можно использовать вызываемый объект. Это позволяет изменять используемое хранилище во время выполнения, например, выбирать разные хранилища для разных сред.
Ваш callable будет оцениваться при загрузке классов ваших моделей и должен возвращать экземпляр 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)
Добавлена поддержка storages
.