Skip to main content
 首页 » 编程设计

python之使用 django 和 sqlite 存储 BLOB 数据

2025年05月04日29虾米姐

首先,我知道有很多类似的问题,但其他解决方案不涵盖我的具体情况:

在我的 sqlite 数据库中有现有的二进制数据(SHA1 和类似的哈希)。通过谷歌搜索和阅读 django-docs我想出了以下内容:

import base64 
 
class BlobField(models.Field): 
"""  
Stores raw binary data 
""" 
 
description = 'Stores raw binary data' 
__metaclass__ = models.SubfieldBase 
 
def __init__(self, *args, **kwds): 
    super(BlobField, self).__init__(*args, **kwds) 
 
def get_internal_type(self): 
    return "BlobField" 
 
def get_db_prep_value(self, value, connection=None, prepared=False): 
    return base64.decodestring(value) 
 
def to_python(self, value): 
    return base64.encodestring(value) 

它做了我想要的,值在正确的时刻被编码和解码,但是在将模型保存到数据库时它给我以下错误:

DatabaseError: You must not use 8-bit bytestrings unless you use a text_factory that can interpret 8-bit bytestrings (like text_factory = str). It is highly recommended that you instead just switch your application to Unicode strings.

我该如何解决这个问题? (可能不会破坏我在应用程序其余部分的所有 unicode 兼容性)

我无法更改数据库列的格式,因为数据已被另一个应用程序使用。


编辑: 正如@filip-dupanovic 所建议的,我采用了 BinaryField 类,如下所示:

BinaryField 类(模型.Field): description = _("原始二进制数据")

def __init__(self, *args, **kwargs): 
    kwargs['editable'] = False 
    super(BinaryField, self).__init__(*args, **kwargs) 
    if self.max_length is not None: 
        self.validators.append(validators.MaxLengthValidator(self.max_length)) 
 
def get_internal_type(self): 
    return "BinaryField" 
 
def get_default(self): 
    if self.has_default() and not callable(self.default): 
        return self.default 
    default = super(BinaryField, self).get_default() 
    if default == '': 
        return b'' 
    return default 
 
def get_db_prep_value(self, value, connection, prepared=False): 
    #value = super(BinaryField, self 
    #    ).get_db_prep_value(value, prepared, connection=connection) 
    #if value is not None: 
    #    return connection.Database.Binary(value) 
    return value 

注意我必须在 get_db_prep_value() 中插入的注释,就像这样,它按预期工作,如果我取消注释这些行,我会得到一个错误

TypeError: get_db_prep_value() got multiple values for keyword argument 'connection'

我可以接受这一点,但不完全理解将其排除在外的含义。即使不调用 super(),它还能工作吗?

请您参考如下方法:

工单#2417 ,关闭不久,添加了一个BinaryField模型字段。你应该看看this commit ,特别是与如何将内部 BlobField 字段类型映射到数据库支持的适当类型相关的更改。