我可以很容易地用文件名填充 Django 夹具中的 FileField 或 ImageField 的字段,但是该文件不存在,当我尝试测试我的应用程序时它会失败,因为该文件不存在。
如何在 Django 固定装置中正确填充 FileField 或 Imagefield,以便文件本身也可用?
恐怕简短的回答是您不能使用 FileField 或 ImageField 类来做到这一点;他们只是存储一个文件路径,对文件的实际数据没有真正的概念。然而,长答案是,如果您利用 Django API 编写您自己的自定义模型字段,那么一切皆有可能。
至少,您需要实现value_to_string
转换数据以进行序列化的方法(上面链接中的 django 文档中有一个示例)。请注意,上面 URL 链接中的示例还提到了子类化 FileField 和 ImageField,这对您的情况很有帮助!
您还必须决定是否应该将数据存储在数据库或文件系统中。如果是前者,您必须将自定义类实现为 Blob 字段,包括为您希望支持的每个 DB 进行自定义;当 HTML 请求 .gif/.jpg/.png/.whatever url 时,您还必须为如何将数据从数据库返回给用户提供一些支持。如果是后者,这是更聪明的方式,恕我直言,您必须实现将二进制数据序列化、反序列化到文件系统的方法。无论哪种方式,如果您将它们实现为 FileField 和 ImageField 的子类,您仍然应该能够使用需要此类 django 功能的管理工具和其他模块。
当且仅当您选择使用更复杂的 blob 方法时,这里有一段代码来自一个处理 MySQL 和 PostgreSQL 的 blob 的旧项目(在我学习 Django 时);您可能会发现一些改进,因为我没有接触过它:-) 但是,它不处理序列化,因此您必须使用上面的方法添加它。
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)
没有办法在序列化的夹具中“包含”文件。如果创建一个测试夹具,你只需要自己做;确保某些测试文件实际存在于 FileField/ImageField 值所引用的位置。这些字段的值是相对于 MEDIA_ROOT 的路径:如果需要,可以设置 MEDIA_ROOT在您的测试 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,所以这应该是可靠的。