如何将上传文件字段添加到 Wagtail 表单?

NVN*_*NVN 5 forms django wagtail

我想让文件上传成为表单页面上可能的 Wagtail 表单字段类型。如何配置模型以使其成为可能?请注意,我对允许用户上传 PDF 之类的文档文件而不是图像更感兴趣。

Loï*_*ira 4

这是LB Johnson 关于此事的一篇精彩文章。下面的代码直接取自文章(但在此处复制以防文章消失),但是您可能需要按照文章进行操作,因为它一步步解释了所有内容。

目前非常复杂,您需要:

  1. 扩展AbstractFormField以定义新的字段类型。
  2. 扩展FormBuilder以处理新的字段类型。
  3. 设置form_builderFormBuilderFormPage 上的自定义类。
  4. 重写serveFormPage 上的方法以将文件数据传递到表单(仅当您使用 Wagtail 1.12 及更低版本时,因为它会从Wagtail 1.13自动执行此操作)
  5. 重写process_form_submission来处理文件

这是完整的代码:

from wagtail.wagtailforms.models import AbstractFormField, FORM_FIELD_CHOICES
from wagtail.wagtailforms.forms import FormBuilder
from wagtail.wagtailimages.fields import WagtailImageField


def filename_to_title(filename):
    from os.path import splitext
    if filename:
        result = splitext(filename)[0]
        result = result.replace('-', ' ').replace('_', ' ')
        return result.title()


class FormField(AbstractFormField):
    FORM_FIELD_CHOICES = list(FORM_FIELD_CHOICES) + [('image', 'Upload Image')]
    field_type = models.CharField(
        verbose_name=_('field type'),
        max_length=16,
        choices=FORM_FIELD_CHOICES)
    page = ParentalKey('FormPage', related_name='form_fields')


class ExtendedFormBuilder(FormBuilder):
    def create_image_upload_field(self, field, options):
        return WagtailImageField(**options)
    FIELD_TYPES = FormBuilder.FIELD_TYPES
    FIELD_TYPES.update({
        'image': create_image_upload_field,
    })


class FormPage(AbstractEmailForm):
    form_builder = ExtendedFormBuilder

    def serve(self, request, *args, **kwargs):
        if request.method == 'POST':
            # form = self.get_form(request.POST, page=self, user=request.user)  # Original line
            form = self.get_form(request.POST, request.FILES, page=self, user=request.user)

            if form.is_valid():
                self.process_form_submission(form)
                return render(
                    request,
                    self.get_landing_page_template(request),
                    self.get_context(request)
                )
        else:
            form = self.get_form(page=self, user=request.user)

        context = self.get_context(request)
        context['form'] = form
        return render(
            request,
            self.get_template(request),
            context
        )

    def process_form_submission(self, form):
        cleaned_data = form.cleaned_data

        for name, field in form.fields.iteritems():
            if isinstance(field, WagtailImageField):
                image_file_data = cleaned_data[name]
                if image_file_data:
                    ImageModel = get_image_model()
                    image = ImageModel(
                        file=cleaned_data[name],
                        title=filename_to_title(cleaned_data[name].name),
                        collection=self.upload_image_to_collection,
                        # assumes there is always a user - will fail otherwise
                        uploaded_by_user=form.user,
                        )
                    image.save()
                    cleaned_data.update({name: image.id})
                else:
                    # remove the value from the data
                    del cleaned_data[name]

        form_data = json.dumps(cleaned_data, cls=DjangoJSONEncoder)
        submission_object = dict(
            page=self,
            form_data=form_data,
            user=form.user,
        )

    intro = RichTextField(blank=True)
    thank_you_text = RichTextField(blank=True)

    FormPage.content_panels = [
        FieldPanel('title', classname="full title"),
        FieldPanel('intro', classname="full"),
        InlinePanel('form_fields', label="Form fields"),
        FieldPanel('thank_you_text', classname="full"),
        MultiFieldPanel([
            FieldRowPanel([
                FieldPanel('from_address', classname="col6"),
                FieldPanel('to_address', classname="col6"),
            ]),
            FieldPanel('subject'),
        ], "Email"),
]
Run Code Online (Sandbox Code Playgroud)

这是处理文档而不是图像的(未经测试的)代码:

from django.forms import FileField
from wagtail.wagtaildocs.models import get_document_model
# Other imports

class FormField(AbstractFormField):
    FORM_FIELD_CHOICES = list(FORM_FIELD_CHOICES) + [('document', 'Upload Document')]
    # `field_type` and `page` remain unchanged


class ExtendedFormBuilder(FormBuilder):
    def create_document_upload_field(self, field, options):
        return FileField(**options)
    FIELD_TYPES = FormBuilder.FIELD_TYPES
    FIELD_TYPES.update({
        'document': create_document_upload_field,
    })

class FormPage(AbstractEmailForm):
    # `form_builder` attribute and `serve` remain unchanged.

    def process_form_submission(self, form):
        cleaned_data = form.cleaned_data

        for name, field in form.fields.iteritems():
            if isinstance(field, FileField):
                document_file_data = cleaned_data[name]
                if document_file_data:
                    DocumentModel = get_document_model()
                    document = DocumentModel(
                        file=cleaned_data[name],
                        title=filename_to_title(cleaned_data[name].name),
                        # assumes there is always a user - will fail otherwise
                        uploaded_by_user=form.user,
                    )
                    document.save()
                    cleaned_data.update({name: document.id})
                else:
                    # remove the value from the data
                    del cleaned_data[name]

        # The rest of the function is unchanged
Run Code Online (Sandbox Code Playgroud)