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

时间:2017-12-21 14:57:02

标签: django forms wagtail

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

2 个答案:

答案 0 :(得分:3)

这是来自LB Johnson的great article。下面的代码直接取自文章(但是在文章消失的情况下复制到此处),但是您可能希望按照文章的说法逐步解释所有内容。

目前它非常活跃,你需要:

  1. 扩展AbstractFormField以定义新的字段类型。
  2. 扩展FormBuilder以处理新字段类型。
  3. form_builder设置为FormPage上的自定义FormBuilder课程。
  4. 覆盖FormPage上的serve方法,将文件数据传递给表单(仅当您使用Wagtail 1.12及以下版本,因为它自动从Wagtail 1.13开始)
  5. 覆盖process_form_submission以处理文件
  6. 以下是完整代码:

    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"),
    ]
    

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

    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
    

答案 1 :(得分:0)

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,
})

FormBuilder没有属性FIELD_TYPES,那么如何添加呢? @LoïcTeixeira