如何在Wagtail API富文本响应中将embed元素替换为img元素?
解决Wagtail API富文本图片返回
<embed>而非<img>的问题 方案1:自定义RichText序列化器
通过重写Wagtail API的富文本序列化器,自动替换响应中的<embed>标签为带图片源的<img>标签。
步骤1:创建自定义序列化器
在你的应用目录下新建serializers.py,写入以下代码:
from wagtail.api.v2.serializers import RichTextSerializer from wagtail.images.models import Image import re class CustomRichTextSerializer(RichTextSerializer): def to_representation(self, value): # 获取原始富文本HTML html = super().to_representation(value) # 匹配图片类型的embed标签 embed_pattern = re.compile(r'<embed alt="([^"]+)" embedtype="image" format="([^"]+)" id="(\d+)"/>') def replace_embed(match): alt_text = match.group(1) image_format = match.group(2) image_id = match.group(3) try: # 根据ID获取图片实例 image = Image.objects.get(id=image_id) # 获取对应格式的图片渲染版本(需和Wagtail后台配置的图片格式匹配) rendition = image.get_rendition(f'fill-{image_format}') # 返回替换后的img标签 return f'<img src="{rendition.url}" alt="{alt_text}" class="{image_format}"/>' except Image.DoesNotExist: # 图片不存在时返回原标签,避免API报错 return match.group(0) # 替换所有匹配的embed标签 modified_html = embed_pattern.sub(replace_embed, html) return modified_html
步骤2:注册自定义API视图集
在项目的API路由配置文件(如api.py)中,替换默认的Pages视图集,指定自定义序列化器:
from wagtail.api.v2.views import PagesAPIViewSet from wagtail.api.v2.router import WagtailAPIRouter from .serializers import CustomRichTextSerializer api_router = WagtailAPIRouter('wagtailapi') class CustomPagesAPIViewSet(PagesAPIViewSet): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 为body字段绑定自定义序列化器 self.serializer_class._declared_fields['body'] = CustomRichTextSerializer() api_router.register_endpoint('pages', CustomPagesAPIViewSet)
方案2:在页面模型中添加处理后的字段
如果不想修改全局API序列化器,可以在页面模型中新增一个处理后的字段,专门返回替换完成的富文本内容。
代码示例
from wagtail.models import Page from wagtail.fields import StreamField from wagtail.api import APIField import re from wagtail.images.models import Image class YourPageModel(Page): body = StreamField(...) # 你的原始富文本字段 # 定义API返回的字段,替换原body为处理后的版本 api_fields = [ APIField('processed_body'), # 其他需要返回的字段... ] @property def processed_body(self): processed_blocks = [] for block in self.body: if block.block_type == 'rich_text': html = block.value # 匹配并替换embed标签,逻辑和方案1一致 embed_pattern = re.compile(r'<embed alt="([^"]+)" embedtype="image" format="([^"]+)" id="(\d+)"/>') def replace_embed(match): alt_text = match.group(1) image_format = match.group(2) image_id = match.group(3) try: image = Image.objects.get(id=image_id) rendition = image.get_rendition(f'fill-{image_format}') return f'<img src="{rendition.url}" alt="{alt_text}" class="{image_format}"/>' except Image.DoesNotExist: return match.group(0) modified_html = embed_pattern.sub(replace_embed, html) processed_blocks.append({ 'type': 'rich_text', 'value': modified_html }) else: # 非富文本块直接保留原始数据 processed_blocks.append(block.serialized_data) return processed_blocks
注意事项
- 图片渲染格式(如
fill-{image_format})需要和你在Wagtail后台配置的图片格式名称对应,比如后台定义的fullwidth格式对应fill-1200x600,需要根据实际情况调整。 - 务必处理
Image.DoesNotExist异常,防止因图片被删除导致API请求失败。
内容的提问来源于stack exchange,提问作者Daniel Erazo
相关产品推荐
相关产品推荐

