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

如何在Wagtail后台实现多图片上传功能(基于Django API架构)

Wagtail后台多图上传功能实现方案

我基于Django、Wagtail及API序列化器进行开发,不直接使用模板渲染HTML,而是通过Django和Wagtail的API功能输出内容。当前需要在后台新增多图片上传功能:默认Wagtail仅支持单次上传单张图片,我需在现有结构中实现wagtail/images/multiple/add路径下的多图上传能力。

现有代码结构如下:

blocks.py

from wagtail.images.blocks import ImageChooserBlock
from wagtail.models import Site, Page
from cms.core.models import get_rootless_url_path
import re
from wagtail.images.models import Image
from wagtail.templatetags.wagtailcore_tags import richtext


class ImageChooserRenditionsAPIBlock(ImageChooserBlock):
    def get_api_representation(self, value, context=None) -> dict:
        from .serializers import ImageSerializer

        return ImageSerializer(value).data


class GreeterBlock(StructBlock):
    label = TextBlock()
    # description = TextBlock()
    description =CustomRichTextBlock(features=['h1', 'h2', 'h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'image', 'code', 'blockquote'] )  
    image = ImageChooserRenditionsAPIBlock(required=False)
    video = CustomDocumentChooserBlock(required=False)
    cards = StreamBlock(
        local_blocks=("cards", CardBlock()),
        required=False,
    )

serializer.py

class ImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_image_model()
        # fields = ("id", "title", "width", "height", "renditions")
        fields = ("id", "title", "width", "height", "file")

urls.py

from django.urls import path, include
from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.documents import urls as wagtaildocs_urls
from wagtail.api.v2.router import WagtailAPIRouter
from wagtail.documents.api.v2.views import DocumentsAPIViewSet
from wagtail.images.api.v2.views import ImagesAPIViewSet
from cms.meta import urls as meta_urls
from .views import CustomPagesAPIViewSet

api_router = WagtailAPIRouter("wagtailapi")
api_router.register_endpoint("pages", CustomPagesAPIViewSet)
api_router.register_endpoint("images", ImagesAPIViewSet)
api_router.register_endpoint("documents", DocumentsAPIViewSet)


urlpatterns = [
    path("", include(wagtailadmin_urls)),
    path("content/documents/", include(wagtaildocs_urls)),
    
]

api_urlpatterns = [
    path("", api_router.urls),
    path("meta/", include(meta_urls.urlpatterns)),
]

实现步骤

1. 编写多图上传视图

在项目的views.py中新增批量图片上传处理逻辑:

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from wagtail.images.models import Image
from wagtail.images.forms import get_image_form
from wagtail.admin.auth import require_admin_access

@require_admin_access
@csrf_exempt
def multiple_image_upload(request):
    if request.method == 'POST':
        ImageForm = get_image_form()
        uploaded_images = []
        # 遍历上传的所有文件
        for file in request.FILES.getlist('files'):
            form = ImageForm(request.POST, request.FILES, instance=Image())
            if form.is_valid():
                image = form.save()
                # 用现有序列化器返回图片数据
                from .serializers import ImageSerializer
                uploaded_images.append(ImageSerializer(image).data)
            else:
                return JsonResponse({'error': form.errors}, status=400)
        
        return JsonResponse({'images': uploaded_images}, status=201)
    return JsonResponse({'error': '仅支持POST请求'}, status=405)

2. 配置多图上传路由

修改urls.py,在urlpatterns中添加对应路由:

from django.urls import path, include
from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.documents import urls as wagtaildocs_urls
from wagtail.api.v2.router import WagtailAPIRouter
from wagtail.documents.api.v2.views import DocumentsAPIViewSet
from wagtail.images.api.v2.views import ImagesAPIViewSet
from cms.meta import urls as meta_urls
from .views import CustomPagesAPIViewSet, multiple_image_upload  # 导入新增视图

api_router = WagtailAPIRouter("wagtailapi")
api_router.register_endpoint("pages", CustomPagesAPIViewSet)
api_router.register_endpoint("images", ImagesAPIViewSet)
api_router.register_endpoint("documents", DocumentsAPIViewSet)


urlpatterns = [
    path("", include(wagtailadmin_urls)),
    path("content/documents/", include(wagtaildocs_urls)),
    # 新增多图上传路由
    path("wagtail/images/multiple/add/", multiple_image_upload, name='multiple_image_upload'),
]

api_urlpatterns = [
    path("", api_router.urls),
    path("meta/", include(meta_urls.urlpatterns)),
]

3. (可选)在区块中支持多图片选择

如果需要在页面区块内直接选择多张图片,修改blocks.py新增多图选择区块:

from wagtail.images.blocks import ImageChooserBlock
from wagtail.models import Site, Page
from cms.core.models import get_rootless_url_path
import re
from wagtail.images.models import Image
from wagtail.templatetags.wagtailcore_tags import richtext
from wagtail.core.blocks import ListBlock, StructBlock, TextBlock, StreamBlock  # 补充导入

class ImageChooserRenditionsAPIBlock(ImageChooserBlock):
    def get_api_representation(self, value, context=None) -> dict:
        from .serializers import ImageSerializer

        return ImageSerializer(value).data

# 新增多图片选择区块
class MultiImageChooserAPIBlock(ListBlock):
    def __init__(self, **kwargs):
        super().__init__(ImageChooserRenditionsAPIBlock(), **kwargs)
    
    def get_api_representation(self, value, context=None):
        return [
            self.child_blocks['image_chooser_renditions_api_block'].get_api_representation(item, context)
            for item in value
        ]

class GreeterBlock(StructBlock):
    label = TextBlock()
    description = CustomRichTextBlock(features=['h1', 'h2', 'h3', 'h4', 'h5', 'bold', 'italic', 'ol', 'ul', 'hr', 'link', 'image', 'code', 'blockquote'])  
    image = ImageChooserRenditionsAPIBlock(required=False)
    multi_images = MultiImageChooserAPIBlock(required=False)  # 添加多图片字段
    video = CustomDocumentChooserBlock(required=False)
    cards = StreamBlock(
        local_blocks=("cards", CardBlock()),
        required=False,
    )

4. (可选)优化序列化器返回缩略图

如果需要API返回不同尺寸的图片缩略图,修改serializer.py:

from rest_framework import serializers
from wagtail.images.models import get_image_model, Rendition
from wagtail.images.shortcuts import get_rendition_or_not_found

class RenditionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Rendition
        fields = ('url', 'width', 'height')

class ImageSerializer(serializers.ModelSerializer):
    renditions = serializers.SerializerMethodField()

    class Meta:
        model = get_image_model()
        fields = ("id", "title", "width", "height", "file", "renditions")
    
    def get_renditions(self, obj):
        # 自定义需要返回的缩略图规格
        rendition_specs = ['fill-300x200', 'max-800x600', 'original']
        renditions = {}
        for spec in rendition_specs:
            rendition = get_rendition_or_not_found(obj, spec)
            renditions[spec] = RenditionSerializer(rendition).data
        return renditions

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 11:07:33