def streamforms_form(context, slug, reference, action=".", **kwargs): """ Renders a form on the page. {% load streamforms_tags %} {% streamforms_form "the-form-slug" "some-unique-reference" "." %} """ try: form = Form.objects.get(slug=slug) block = WagtailFormBlock() # the context is a RequestContext, we need to turn it into a dict or # the blocks in wagtail will start to fail with dict(context) return block.render( block.to_python({ "form": form.pk, "form_action": action, "form_reference": reference }), context.flatten(), ) except Form.DoesNotExist: return mark_safe("")
def test_clean_adds_form_reference(self): block = WagtailFormBlock() value = block.clean({ 'form': self.form.pk, 'form_action': '/foo/' }) self.assertIsNotNone(value.get('form_reference'))
def test_clean_keeps_existing_form_reference(self): block = WagtailFormBlock() value = block.clean({ 'form': self.form.pk, 'form_action': '/foo/', 'form_reference': 'some-ref' }) self.assertEqual(value.get('form_reference'), 'some-ref')
def test_context_has_form(self): block = WagtailFormBlock() context = block.get_context(block.to_python({ 'form': self.form.pk, 'form_action': '/foo/', 'form_reference': 'some-ref' })) self.assertIsNotNone(context['form'])
def test_clean_keeps_existing_form_reference(self): block = WagtailFormBlock() value = block.clean({ "form": self.form.pk, "form_action": "/foo/", "form_reference": "some-ref" }) self.assertEqual(value.get("form_reference"), "some-ref")
def test_context_has_form(self): block = WagtailFormBlock() context = block.get_context( block.to_python({ "form": self.form.pk, "form_action": "/foo/", "form_reference": "some-ref", })) self.assertIsNotNone(context["form"])
def test_render_when_form_deleted(self): block = WagtailFormBlock() html = block.render( block.to_python({ "form": 100, "form_action": "/foo/", "form_reference": "some-ref" })) expected_html = "\n".join( ["<p>Sorry, this form has been deleted.</p>"]) self.assertHTMLEqual(html, expected_html)
def test_render_when_form_deleted(self): block = WagtailFormBlock() html = block.render(block.to_python({ 'form': 100, 'form_action': '/foo/', 'form_reference': 'some-ref' })) expected_html = '\n'.join([ '<p>Sorry, this form has been deleted.</p>', ]) self.assertHTMLEqual(html, expected_html)
def test_context_form_is_invalid_when_parent_context_has_this_form_with_errors( self, ): invalid_form = self.form.get_form({ "form_id": self.form.id, "form_reference": "some-ref" }) assert not invalid_form.is_valid() self.assertDictEqual( invalid_form.errors, { "singleline": ["This field is required."], "multiline": ["This field is required."], "date": ["This field is required."], "datetime": ["This field is required."], "email": ["This field is required."], "url": ["This field is required."], "number": ["This field is required."], "dropdown": ["This field is required."], "radio": ["This field is required."], "checkboxes": ["This field is required."], "checkbox": ["This field is required."], "hidden": ["This field is required."], "singlefile": ["This field is required."], "multifile": ["This field is required."], }, ) # this is the context a page will set for an invalid form parent_context = { "invalid_stream_form_reference": "some-ref", "invalid_stream_form": invalid_form, } block = WagtailFormBlock() # get a new block context context = block.get_context( block.to_python({ "form": self.form.pk, "form_action": "/foo/", "form_reference": "some-ref", }), parent_context, ) # finally make sure the form in the block is the one with errors self.assertEqual(context["form"], invalid_form)
class FlexPage(ExportModelOperationsMixin("flex_page"), MetadataPageMixin, Page): body = StreamField( [ ("header", MyHeaderBlock()), ("list", ListBlock()), ("image_text_overlay", ImageTextOverlayBlock()), ("cropped_images_with_text", CroppedImagesWithTextBlock()), ("list_with_images", ListWithImagesBlock()), ("thumbnail_gallery", ThumbnailGalleryBlock()), ("chart", ChartBlock()), ("map", MapBlock()), ("image_slider", ImageSliderBlock()), ("form", WagtailFormBlock()), ("Parallax", ParallaxBlock()), ("Code", MyCodeBlock()), ("Timeline", TimelineBlock()), ("Text", blocks.RichTextBlock()), ("Quote", blocks.BlockQuoteBlock()), ("Embed", EmbedBlock()), ("Document", DocumentChooserBlock()), ], blank=True, ) author_twitter_handle = models.CharField(max_length=15) content_panels = Page.content_panels + [ StreamFieldPanel("body", classname="Full"), FieldPanel("author_twitter_handle"), ]
class PostPage(Page): body = StreamField( [('content', RichTextBlock()), ('form', WagtailFormBlock())], null=True, blank=True, ) content_panels = Page.content_panels + [StreamFieldPanel('body')]
def test_context_form_is_invalid_when_parent_context_has_this_form_with_errors( self): invalid_form = self.form.get_form({ 'form_id': self.form.id, 'form_reference': 'some-ref' }) assert not invalid_form.is_valid() self.assertDictEqual( invalid_form.errors, { 'singleline': ['This field is required.'], 'multiline': ['This field is required.'], 'date': ['This field is required.'], 'datetime': ['This field is required.'], 'email': ['This field is required.'], 'url': ['This field is required.'], 'number': ['This field is required.'], 'dropdown': ['This field is required.'], 'multiselect': ['This field is required.'], 'radio': ['This field is required.'], 'checkboxes': ['This field is required.'], 'checkbox': ['This field is required.'], 'hidden': ['This field is required.'], 'singlefile': ['This field is required.'], 'multifile': ['This field is required.'] }) # this is the context a page will set for an invalid form parent_context = { 'invalid_stream_form_reference': 'some-ref', 'invalid_stream_form': invalid_form } block = WagtailFormBlock() # get a new block context context = block.get_context( block.to_python({ 'form': self.form.pk, 'form_action': '/foo/', 'form_reference': 'some-ref' }), parent_context) # finally make sure the form in the block is the one with errors self.assertEqual(context['form'], invalid_form)
class ContactPage(TranslatablePage): intro = RichTextField(blank=True) body = StreamField([ ('paragraph', blocks.RichTextBlock()), ('form', WagtailFormBlock()), ]) content_panels = TranslatablePage.content_panels + [ FieldPanel('intro'), StreamFieldPanel('body'), ]
class ContactPage(TranslatablePage): intro = RichTextField(blank=True) body = StreamField([ ("paragraph", blocks.RichTextBlock()), ("form", WagtailFormBlock()), ]) content_panels = TranslatablePage.content_panels + [ FieldPanel("intro"), StreamFieldPanel("body"), ]
class BasicPage(Page): body = StreamField([('rich_text', blocks.RichTextBlock()), ('form', WagtailFormBlock())]) # show in menu ticked by default show_in_menus_default = True content_panels = Page.content_panels + [ StreamFieldPanel('body'), ]
def test_context_form_is_invalid_when_parent_context_has_this_form_with_errors(self): invalid_form = self.form.get_form({'form_id': self.form.id, 'form_reference': 'some-ref'}) assert not invalid_form.is_valid() self.assertEqual(invalid_form.errors, {'name': ['This field is required.']}) # this is the context a page will set for an invalid form parent_context = { 'invalid_stream_form_reference': 'some-ref', 'invalid_stream_form': invalid_form } block = WagtailFormBlock() # get a new block context context = block.get_context(block.to_python({ 'form': self.form.pk, 'form_action': '/foo/', 'form_reference': 'some-ref' }), parent_context) # finally make sure the form in the block is the one with errors self.assertEqual(context['form'], invalid_form)
def test_render(self): block = WagtailFormBlock() html = block.render(block.to_python({ 'form': self.form.pk, 'form_action': '/foo/', 'form_reference': 'some-ref' })) expected_html = '\n'.join([ '<h2>Basic Form</h2>', '<form action="/foo/" method="post" novalidate>', '<input id="id_form_id" name="form_id" type="hidden" value="%s">' % self.form.pk, '<input id="id_form_reference" name="form_reference" type="hidden" value="some-ref">', '<div class="field-row">', '<label for="id_name">Name</label>', '<input type="text" name="name" maxlength="255" required id="id_name" />', '<p class="help-text">Please enter your name</p>', '</div>', '<input type="submit" value="Submit">', '</form>', ]) self.assertHTMLEqual(html, expected_html)
class FormPage(TranslatablePage): intro = RichTextField(blank=True) image = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') body = StreamField([ ('form', WagtailFormBlock()), ]) content_panels = TranslatablePage.content_panels + [ FieldPanel('intro'), ImageChooserPanel('image'), StreamFieldPanel('body'), ]
class BaseStreamBlock(StreamBlock): """ Define the custom blocks that `StreamField` will utilize """ heading_block = HeadingBlock() paragraph_block = RichTextBlock(icon="fa-paragraph", template="blocks/paragraph_block.html") image_block = ImageBlock() block_quote = BlockQuote() embed_block = EmbedBlock( help_text= 'Insert an embed URL e.g https://www.youtube.com/embed/SGJFWirQ3ks', icon="fa-s15", template="blocks/embed_block.html") counter_panel = CounterPanel() process_panel = ProcessPanel() services_panel = ServicePanel() streamform = WagtailFormBlock()
class HomePage(MetadataPageMixin, Page): body = StreamField( [ ("header", HeaderBlock()), ("list", ListBlock()), ("image_text_overlay", ImageTextOverlayBlock()), ("cropped_images_with_text", CroppedImagesWithTextBlock()), ("list_with_images", ListWithImagesBlock()), ("thumbnail_gallery", ThumbnailGalleryBlock()), ("chart", ChartBlock()), ("map", MapBlock()), ("image_slider", ImageSliderBlock()), ("form", WagtailFormBlock()), ("Parallax", ParallaxBlock()), ("Code", MyCodeBlock()), ], blank=True, ) author_twitter_handle = models.CharField(max_length=15) content_panels = Page.content_panels + [ StreamFieldPanel("body", classname="Full"), FieldPanel("author_twitter_handle"), ]
class HomePage(TranslatablePage): """Home page model.""" max_count = 1 service_title = models.CharField(_("Service title"), max_length=50) service_body = RichTextField(_("Service body"), blank=True) member_link = models.ForeignKey( TranslatablePage, verbose_name=_("Link to be a member"), blank=True, null=True, on_delete=models.PROTECT, related_name='+', help_text=_("Page to link to"), ) form = StreamField([ ('form', WagtailFormBlock()), ], blank=True, null=True) content_panels = TranslatablePage.content_panels + [ MultiFieldPanel( [InlinePanel("carousel_images", min_num=1, label=_("Image"))], heading=_("Carousel Images"), ), MultiFieldPanel([ FieldPanel("service_title"), FieldPanel("service_body"), InlinePanel("services", min_num=1, max_num=3, label=_("Service")) ], heading=_("Services")), FieldPanel("member_link"), MultiFieldPanel([ InlinePanel("why_choose_us", min_num=1, max_num=3, label=_("Item")) ], heading=_("Why choose us")), StreamFieldPanel('form'), ]
class AbstractSectionItem(models.Model): background = models.ForeignKey( 'general.Style', on_delete=models.PROTECT, limit_choices_to={'category__title': 'BackgroundColour'}, related_name='+', help_text="The background colour." ) background_width = models.ForeignKey( 'general.Style', on_delete=models.PROTECT, limit_choices_to={'category__title': 'BackgroundWidth'}, related_name='+', help_text="The area to cover the background." ) vertical_padding = models.ForeignKey( 'general.Style', on_delete=models.PROTECT, limit_choices_to={'category__title': 'VerticalPadding'}, related_name='+', help_text="The vertical space between the section and the content." ) content_width = models.ForeignKey( 'general.Style', on_delete=models.PROTECT, limit_choices_to={'category__title': 'ContainerWidth'}, related_name='+', help_text="The width of the content." ) horizontal_padding = models.ForeignKey( 'general.Style', on_delete=models.PROTECT, limit_choices_to={'category__title': 'HorizontalPadding'}, related_name='+', help_text="The horizontal space between set content_width and the content." ) text_alignment = models.ForeignKey( 'general.Style', on_delete=models.PROTECT, limit_choices_to={'category__title': 'TextAlignment'}, related_name='+', help_text="The text alignment of the content." ) text_colour = models.ForeignKey( 'general.Style', on_delete=models.PROTECT, limit_choices_to={'category__title': 'TextColour'}, related_name='+', help_text="The text colour of the content." ) content = StreamField( [ ('heading', HeadingBlock()), ('paragraph', blocks.RichTextBlock()), ('markdown', MarkDownBlock(rows=10)), ('image', ImageBlock()), ('pullquote', QuoteBlock()), ('embed', EmbedBlock()), ('form', WagtailFormBlock()), ('link', LinkBlock()), ('custom_content', SnippetChooserBlock('general.CustomContent')), ('card_list', CardListBlock()), ('two_column', TwoColumnBlock()) ], null=True, blank=True ) class Meta: abstract = True panels = [ FieldRowPanel([ FieldPanel('background'), FieldPanel('background_width'), FieldPanel('content_width'), ]), FieldRowPanel([ FieldPanel('vertical_padding'), FieldPanel('horizontal_padding'), FieldPanel('text_alignment'), ]), FieldRowPanel([ FieldPanel('text_colour', classname='col4'), ]), StreamFieldPanel('content', classname='full-width-multiple-stream-field'), ]
class HomePage(Page): project_name = models.CharField( max_length=255, blank=True, ) project_tagline = models.CharField( max_length=255, blank=True, ) cover = models.ForeignKey('wagtailimages.Image', null=True, blank=True, on_delete=models.SET_NULL, related_name='+') about_text_left = models.CharField( max_length=500, blank=True, ) about_text_right = models.CharField( max_length=500, blank=True, ) team_text_left = models.CharField( max_length=500, blank=True, ) team_text_right = models.CharField( max_length=500, blank=True, ) contact_text = models.CharField( max_length=255, blank=True, ) first_line_location = models.CharField( max_length=255, blank=True, ) second_line_location = models.CharField( max_length=255, blank=True, ) contact_body = StreamField([ ('form', WagtailFormBlock()), ]) content_panels = Page.content_panels + [ FieldPanel('project_name', classname="full"), FieldPanel('project_tagline', classname="full"), ImageChooserPanel('cover'), FieldPanel('about_text_left', classname="full"), FieldPanel('about_text_right', classname="full"), FieldPanel('team_text_left', classname="full"), FieldPanel('team_text_right', classname="full"), FieldPanel('contact_text', classname="full"), FieldPanel('first_line_location', classname="full"), FieldPanel('second_line_location', classname="full"), StreamFieldPanel('contact_body'), ]
def test_clean_adds_form_reference(self): block = WagtailFormBlock() value = block.clean({"form": self.form.pk, "form_action": "/foo/"}) self.assertIsNotNone(value.get("form_reference"))
def test_render(self): block = WagtailFormBlock() html = block.render( block.to_python({ "form": self.form.pk, "form_action": ".", "form_reference": "some-ref" })) expected_html = "\n".join([ "<h2>Basic Form</h2>", '<form action="." enctype="multipart/form-data" method="post" novalidate>', '<input type="hidden" name="hidden" id="id_hidden" />', '<input id="id_form_id" name="form_id" type="hidden" value="%s">' % self.form.pk, '<input id="id_form_reference" name="form_reference" type="hidden" value="some-ref">', '<div class="field-row">' '<label for="id_singleline">singleline</label>' '<input type="text" name="singleline" required id="id_singleline" />' '<p class="help-text">Help</p>' "</div>", '<div class="field-row">' '<label for="id_multiline">multiline</label>' '<textarea name="multiline" cols="40" rows="10" required id="id_multiline">' "</textarea>" '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_date">date</label>' '<input type="text" name="date" value="" required id="id_date" />' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_datetime">datetime</label>' '<input type="text" name="datetime" value="" required id="id_datetime" />' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_email">email</label>' '<input type="email" name="email" required id="id_email" />' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_url">url</label>' '<input type="url" name="url" required id="id_url" />' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_number">number</label>' '<input type="number" name="number" step="any" required id="id_number" />' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_dropdown">dropdown</label>' '<select name="dropdown" id="id_dropdown">' '<option value="Option 1">Option 1</option>' '<option value="Option 2">Option 2</option>' '<option value="Option 3">Option 3</option></select>' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_radio_0">radio</label>' '<ul id="id_radio">' '<li><label for="id_radio_0">' '<input type="radio" name="radio" value="Option 1" required id="id_radio_0" /> Option 1' "</label></li>" '<li><label for="id_radio_1">' '<input type="radio" name="radio" value="Option 2" required id="id_radio_1" /> Option 2' "</label></li>" '<li><label for="id_radio_2">' '<input type="radio" name="radio" value="Option 3" required id="id_radio_2" /> Option 3' "</label></li></ul>" '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' "<label>checkboxes</label>" '<ul id="id_checkboxes">' '<li><label for="id_checkboxes_0">' '<input type="checkbox" name="checkboxes" value="Option 1" id="id_checkboxes_0" /> Option 1' "</label></li>" '<li><label for="id_checkboxes_1">' '<input type="checkbox" name="checkboxes" value="Option 2" id="id_checkboxes_1" /> Option 2' "</label></li>" '<li><label for="id_checkboxes_2">' '<input type="checkbox" name="checkboxes" value="Option 3" id="id_checkboxes_2" /> Option 3' "</label></li></ul>" '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_checkbox">checkbox</label>' '<input type="checkbox" name="checkbox" required id="id_checkbox" />' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_singlefile">singlefile</label>' '<input type="file" name="singlefile" required id="id_singlefile" />' '<p class="help-text">Help</p>' "</div>" '<div class="field-row">' '<label for="id_multifile">multifile</label>' '<input type="file" name="multifile" multiple required id="id_multifile" />' '<p class="help-text">Help</p>' "</div>" '<input type="submit" value="Submit">' "</form>", ]) self.assertHTMLEqual(html, expected_html)
class BasicPage(Page): body = StreamField([ ('heading', blocks.CharBlock(classname="full title")), ('paragraph', blocks.RichTextBlock()), ('image', ImageChooserBlock()), ('table', TableBlock()), ('BlockQuoteBlock', BlockQuoteBlock()), ('URLBlock', URLBlock()), ('EmailBlock', EmailBlock()), ('DateBlock', DateBlock()), ('TimeBlock', TimeBlock()), ('DateTimeBlock', DateBlock()), ('PageChooserBlock', PageChooserBlock()), ('DocumentChooserBlock', DocumentChooserBlock()), ('IframeBlock', TextBlock()), ('EmbedBlock', EmbedBlock()), ('form', WagtailFormBlock()), ('show_business_hours', BooleanBlock( required=False, help_text="If checked, the library hours will display on the page", template='basic_page/blocks/business_hours.html', icon='user')), ('show_next_closure', BooleanBlock( required=False, help_text="If checked, the next library closure will display", template='basic_page/blocks/next_closure.html', icon='user')), ('show_all_closures', BooleanBlock( required=False, help_text= "If checked, all upcoming library closures will be shown", template='basic_page/blocks/all_closures.html', icon='user')), ('map', blocks.StructBlock([ ('address', GeoAddressBlock(required=True)), ('map', GeoBlock(address_field='address')), ], template='basic_page/blocks/map.html', icon='user')), ('bookClub', blocks.StructBlock( [('book_club_name', blocks.CharBlock()), ('book_club_day_of_the_week', blocks.TextBlock()), ('book_club_PDF', DocumentChooserBlock(required=False)), ('book_club_time', blocks.TimeBlock()), ('books', blocks.StreamBlock([ ( 'book', blocks.StructBlock( [ ('book_name', blocks.CharBlock()), ('author_name', blocks.CharBlock()), ('reading_date', blocks.DateBlock()), ('book_description', blocks.RichTextBlock()), ('book_cover', ImageChooserBlock(required=False)), ], template='basic_page/blocks/books.html'), ), ]))], template='basic_page/blocks/book_club.html', icon='openquote')), ('panel', blocks.StructBlock([ ('panel_name', blocks.CharBlock()), ('show_by_default', blocks.BooleanBlock( required=False, help_text="Display Panel as open by default")), ('panel_body', blocks.StreamBlock([ ( 'panel_items', blocks.StructBlock([ ('panel_item_title', blocks.CharBlock()), ('panel_link', URLBlock( required=False, help_text="Use this for images you wish to link" )), ('panel_image', ImageChooserBlock( required=False, help_text="Use this for images you wish to link" )), ('panel_description', blocks.RichTextBlock()), ], template= 'basic_page/blocks/panel_items.html'), ), ])) ], template='basic_page/blocks/panel.html', icon='collapse-down')), ], blank=True) def get_context(self, request): data = super(BasicPage, self).get_context(request) return data content_panels = Page.content_panels + [ StreamFieldPanel('body'), ] # Search index configuration search_fields = Page.search_fields + [ index.SearchField('body'), ]