Как вы положили файл в приспособление в Django? - PullRequest
10 голосов
/ 17 апреля 2009

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

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

Ответы [ 2 ]

7 голосов
/ 20 апреля 2009

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

РЕДАКТИРОВАТЬ : Если вы хотите сделать это с помощью метода 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 , так что это должно быть надежно.

7 голосов
/ 19 апреля 2009

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

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

Вам также придется решить, следует ли хранить данные в базе данных или в файловой системе. Если первое, вам придется реализовать свой пользовательский класс как поле Blob, включая настройку для каждой БД, которую вы хотите поддерживать; вам также потребуется обеспечить некоторую поддержку того, как данные должны быть возвращены пользователю из базы данных, когда HTML-запрос запрашивает URL-адрес .gif / .jpg / .png / .whwh. Если последний вариант, который является наиболее разумным способом ИМХО, вам придется реализовать методы для сериализации, десериализации двоичных данных в файловой системе. В любом случае, если вы реализуете их как подклассы FileField и ImageField, вы все равно сможете использовать инструменты администратора и другие модули, которые ожидают таких возможностей 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)
...