Как вы помещаете файл в устройство в Django?

Я могу легко заполнить поле FileField или ImageField в устройстве Django с именем файла, но этот файл не существует, и когда я пытаюсь протестировать мое приложение, он терпит неудачу, потому что этот файл не существует.

Как правильно заполнить FileField или Imagefield в устройстве Django, чтобы сам файл был доступен?

Ответ 1

Я боюсь, что короткий ответ заключается в том, что вы не можете сделать это, используя классы FileField или ImageField; они просто хранят путь к файлу и не имеют реальной концепции фактических данных файла. Однако длинный ответ заключается в том, что все возможно, если вы используете API Django для написания собственных настраиваемых полей модели.

Как минимум, вы захотите реализовать метод value_to_string для преобразования данных для сериализации (там пример в django docs по ссылке выше). Обратите внимание, что примеры в ссылке URL выше также включают упоминание подкласса FileField и ImageField, что полезно для вашей ситуации!

Вам также придется решить, следует ли хранить данные в базе данных или в файловой системе. Если первый, вам придется реализовать свой собственный класс в качестве поля Blob, включая настройку для каждого DB, который вы хотите поддержать; вам также необходимо будет предоставить некоторую поддержку тому, как данные должны быть возвращены пользователю из базы данных, когда HTML запрашивает файл .gif/.jpg/.png/.which. Если последнее, что является более разумным способом выхода IMHO, вам придется реализовать методы для сериализации, де-сериализации двоичных данных в файловой системе. В любом случае, если вы реализуете их как подклассы FileField и ImageField, вы все равно сможете использовать инструменты Admin и другие модули, которые ожидают такие функции django.

Если и только если вы решите использовать более активный подход blob, здесь приведен фрагмент кода из старого проекта разума (когда я изучал Django), который обрабатывает blob для MySQL и PostgreSQL; вы, вероятно, сможете найти ряд улучшений, поскольку я не коснулся его с тех пор:-) Он не обрабатывает сериализацию, поэтому вам придется добавить это, используя метод выше.

from django.db import models
from django.conf import settings

class BlobValueWrapper(object):
    """Wrap the blob value so that we can override the unicode method.
    After the query succeeds, Django attempts to record the last query
    executed, and at that point it attempts to force the query string
    to unicode. This does not work for binary data and generates an
    uncaught exception.
    """
    def __init__(self, val):
        self.val = val

    def __str__(self):
        return 'blobdata'

    def __unicode__(self):
        return u'blobdata'


class BlobField(models.Field):
    """A field for persisting binary data in databases that we support."""
    __metaclass__ = models.SubfieldBase

    def db_type(self):
        if settings.DATABASE_ENGINE == 'mysql':
            return 'LONGBLOB'
        elif settings.DATABASE_ENGINE == 'postgresql_psycopg2':
            return 'bytea'
        else:
            raise NotImplementedError

    def to_python(self, value):
        if settings.DATABASE_ENGINE == 'postgresql_psycopg2':
            if value is None:
                return value
            return str(value)
        else:
            return value

    def get_db_prep_save(self, value):
        if value is None:
            return None
        if settings.DATABASE_ENGINE =='postgresql_psycopg2':
            return psycopg2.Binary(value)
        else:
            return BlobValueWrapper(value)

Ответ 2

Невозможно "включить" файлы в сериализованное устройство. Если вы создаете тестовое устройство, вам просто нужно сделать это самостоятельно; убедитесь, что некоторые тестовые файлы действительно существуют в местах, на которые ссылаются значения FileField/ImageField. Значения этих полей являются путями относительно MEDIA_ROOT: если вам нужно, вы можете установить MEDIA_ROOT в свой метод testUp() в пользовательском test_settings.py, чтобы убедиться, что ваши тестовые файлы найдены везде, где вы поместите их.

EDIT. Если вы хотите сделать это в своем методе setUp(), вы можете также monkeypatch default_storage напрямую:

from django.core.files.storage import default_storage

class MyTest(TestCase):

  def setUp(self):
    self._old_default_storage_location = default_storage.location
    default_storage.location = '/some/other/place'

  def tearDown(self):
    default_storage.location = self._old_default_storage_location

Это похоже на работу. default_storage документированный общедоступный API, поэтому это должно быть надежным.