You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Elasticsearch DSL适配Hashid自定义模型字段报错如何解决?

问题原因

你遇到的两个错误分属两个独立问题:

  1. 第一个序列化错误:django-elasticsearch-dsl默认无法识别Hashid自定义类型,不能自动将其序列化为Elasticsearch支持的基础类型
  2. 第二个mapper解析错误:你自定义的HashIdField指定了name = "hashid",但Elasticsearch本身不存在hashid这个字段类型,所以创建索引映射时失败

解决方法

方法1:无需自定义字段的最简方案

直接利用字段的attr参数获取Hashid的字符串值即可,不用额外开发自定义字段类:

@registry.register_document
class ArtworkFeedItemDocument(Document):
    # 如果ArtworkFeedItem自身的主键也是Hashid类型,需要加这行指定主键序列化规则
    id = fields.KeywordField(attr='id.hashid')

    class Index:
        name = 'feed'
        settings = {
            'number_of_shards': 1,
            'number_of_replicas': 0
        }

    artwork = fields.ObjectField(
        properties={
            # 直接指定attr获取Hashid实例的字符串值,用KeywordField更适合ID类型(无需分词)
            'id': fields.KeywordField(attr='id.hashid'),
            'title': fields.TextField(
                attr='title',
                fields={
                    'suggest': fields.Completion(),
                }
            )
        }
    )

    class Django:
        model = ArtworkFeedItem
        fields = []
        related_models = [Artwork]

    # 关联对象更新时触发索引更新的回调,可选但建议添加
    def get_instances_from_related(self, related_instance):
        if isinstance(related_instance, Artwork):
            return ArtworkFeedItem.objects.filter(artwork=related_instance)
        return super().get_instances_from_related(related_instance)

如果str(hashid实例)直接就能返回编码后的字符串,也可以把attr='id.hashid'改成attr='id'。


方法2:自定义可复用的HashId字段

如果多处需要用到Hashid类型的字段,可以修改你的自定义字段实现,让它继承自Elasticsearch已有的KeywordField类型:

from elasticsearch_dsl import KeywordField
from hashid_field.hashid import Hashid

class HashIdField(KeywordField):
    """
    适配Hashid的自定义DSL字段
    底层用Elasticsearch的keyword类型存储,自动序列化Hashid实例为字符串
    """
    def _serialize(self, data):
        if isinstance(data, Hashid):
            # 两种方式选一个能正常拿到编码后字符串的即可
            # return data.hashid
            return str(data)
        return super()._serialize(data)

之后在Document中直接使用即可:

artwork = fields.ObjectField(
    properties={
        'id': HashIdField(),
        'title': fields.TextField(
            attr='title',
            fields={
                'suggest': fields.Completion(),
            }
        )
    }
)

内容的提问来源于stack exchange,提问作者fpghost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 07:36:02