Django Elasticsearch DSL适配Hashid自定义模型字段报错如何解决?
问题原因
你遇到的两个错误分属两个独立问题:
- 第一个序列化错误:django-elasticsearch-dsl默认无法识别
Hashid自定义类型,不能自动将其序列化为Elasticsearch支持的基础类型 - 第二个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
相关产品推荐
相关产品推荐

