如何将文件放入 Django 的固定装置中?

发布于 2024-07-17 09:33:47 字数 161 浏览 6 评论 0原文

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

如何在 Django 固定装置中正确填充 FileField 或 Imagefield 以便文件本身也可用?

I can easily fill the field of a FileField or ImageField in a Django fixture with a file name, but that file doesn't exist and when I try to test my application it fails because that file doesn't exist.

How do I correctly populate a FileField or Imagefield in a Django fixture so that the file itself is available too?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

零度℉ 2024-07-24 09:33:47

恐怕简短的答案是你不能使用 FileField 或 ImageField 类来做到这一点; 它们只存储文件路径,对文件的实际数据没有真正的概念。 然而,长的答案是,如果您利用 Django API 编写自己的 自定义模型字段

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

您还必须决定数据是否应该存储在数据库中或文件系统中。 如果是前者,您将必须将自定义类实现为 Blob 字段,包括对您希望支持的每个数据库进行自定义; 您还必须提供一些支持,以了解当 HTML 请求 .gif/.jpg/.png/.whatever url 时,如何将数据从数据库返回给用户。 如果是后者,恕我直言,这是更明智的方法,您将必须实现将二进制数据序列化、反序列化到文件系统的方法。 无论哪种方式,如果您将它们实现为 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)

I'm afraid the short answer is that you can't do this using the FileField or ImageField classes; they just store a file path and have no real concept of the file's actual data. The long answer, however, is that anything is possible if you leverage the Django API for writing your own custom model fields.

At a minimum, you'll want to implement the value_to_string method to convert the data for serialization (there's an example in the django docs at the link above). Note that the examples at the URL link above also include mention of subclassing FileField and ImageField, which is helpful for your situation!

You'll also have to decide if the data should therefore be stored in the database, or on the file system. If the former, you will have to implement your custom class as a Blob field, including customization for every DB you wish to support; you'll also have to provide some support for how the data should be returned to the user out of the database when the HTML requests a .gif/.jpg/.png/.whatever url. If the latter, which is the smarter way to go IMHO, you'll have to implement methods for serializing, de-serializing binary data to the filesystem. Either way, if you implement these as subclasses of FileField and ImageField, you should still be able to use the Admin tools and other modules that expect such django features.

If and only if you elect to use the more involved blob approach, here's a snippet of code from an old project of mind (back when I was learning Django) that handles blob for MySQL and PostgreSQL; you'll probably be able to find a number of improvements as I haven't touched it since :-) It does not handle serialization, though, so you'll have to add that using the method above.

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)
墟烟 2024-07-24 09:33:47

无法将文件“包含”在序列化的装置中。 如果创建测试夹具,您只需要自己做; 确保某些测试文件确实存在于 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 是记录的公共 API,所以这应该是可靠的。

There's no way to "include" the files in the serialized fixture. If creating a test fixture, you just need to do it yourself; make sure that some test files actually exist in locations referenced by the FileField/ImageField values. The values of those fields are paths relative to MEDIA_ROOT: if you need to, you can set MEDIA_ROOT in your test setUp() method in a custom test_settings.py to ensure that your test files are found wherever you put them.

EDIT: If you want to do it in your setUp() method, you can also monkeypatch default_storage directly:

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

That seems to work. default_storage is a documented public API, so this should be reliable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文