你如何将文件放在Django的夹具中?

时间:2009-04-17 06:50:38

标签: django testing fixture

我可以使用文件名轻松填充Django夹具中的FileField或ImageField字段,但该文件不存在,当我尝试测试我的应用程序时,它失败,因为该文件不存在。

如何正确填充Django夹具中的FileField或Imagefield,以便文件本身也可用?

2 个答案:

答案 0 :(得分:7)

我担心简短的回答是你不能使用FileField或ImageField类来做到这一点;它们只存储文件路径,并且没有文件实际数据的真实概念。然而,长期的答案是,如果您利用Django API编写自己的custom model fields,一切皆有可能。

至少,您需要实现value_to_string方法来转换数据以进行序列化(在上面链接的django文档中有一个示例)。请注意,上面URL链接中的示例还包括提及子类化FileField和ImageField,这对您的情况很有帮助!

您还必须决定数据是否应该存储在数据库或文件系统中。如果是前者,则必须将自定义类实现为Blob字段,包括您希望支持的每个数据库的自定义;当HTML请求.gif / .jpg / .png / .whatever网址时,您还必须为如何将数据从数据库返回给用户提供一些支持。如果后者,这是更智能的方式去IMHO,你将不得不实现序列化,反序列化二进制数据到文件系统的方法。无论哪种方式,如果将它们实现为FileField和ImageField的子类,您仍然可以使用管理工具和期望此类django功能的其他模块。

当且仅当你选择使用更复杂的blob方法时,这里有一段代码来自旧的心灵项目(当我学习Django时),它处理MySQL和PostgreSQL的blob;你可能能够找到一些改进,因为我没有触及它,因为:-)它不处理序列化,所以你必须使用上面的方法添加它。

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)

答案 1 :(得分:7)

无法在序列化夹具中“包含”文件。如果要创建一个测试夹具,你只需要自己动手;确保某些测试文件实际存在于FileField / ImageField值引用的位置。这些字段的值是相对于MEDIA_ROOT的路径:如果需要,可以在自定义test_settings.py中的测试setUp()方法中设置MEDIA_ROOT ,以确保在任何地方找到测试文件把它们放进去。

编辑:如果您想在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是a documented public API,所以这应该是可靠的。