Integrate a custom form with a wagtail page

3,924 views
Skip to first unread message

YusufSalahAdDin

unread,
Feb 10, 2015, 12:42:57 AM2/10/15
to wag...@googlegroups.com
Goodnight Friends.
I have a question.
I created a model for clients and I am creating a form for that model of registering that customer.
I want to create a page that integrates wagtail fields for the page and the registration form, so you can display the page and register the client from there.

At first glance I thought it was easy, but I've seen the form page show and is not as easy as I thought, any recommendation to do so?

Thank you very much for your help.

YusufSalahAdDin

unread,
Feb 12, 2015, 1:00:23 AM2/12/15
to wag...@googlegroups.com
Can anyone help me please?

Dan Braghis

unread,
Feb 12, 2015, 6:05:08 AM2/12/15
to wag...@googlegroups.com
Hi Yusuf,

It really depends on what the model has. In general terms, Wagtail is a Django app, so a lot of approaches that apply to Django apps apply to Wagtail sites as well. So you could create your custom Django form/view that programatically creates a new client object. Or you can use wagtailforms to build the form, then override process_form_submission (see https://github.com/torchbox/wagtail/blob/master/wagtail/wagtailforms/models.py#L134) to create/save the new client object.

In both cases the code to actually create the client object would be something along the lines of:
client = ClientPage()

client.title = 'the client name'
client.slug = 'the-slug'
# ...
# other fields from the form submission


    client.save()

Hope this helps.

Best,
Dan

--
You received this message because you are subscribed to the Google Groups "Wagtail" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wagtail+u...@googlegroups.com.
To post to this group, send email to wag...@googlegroups.com.
Visit this group at http://groups.google.com/group/wagtail.
To view this discussion on the web, visit https://groups.google.com/d/msgid/wagtail/5a4698f4-ab4c-406b-b5c4-c288a82a53da%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

YusufSalahAdDin

unread,
Feb 16, 2015, 9:15:03 PM2/16/15
to wag...@googlegroups.com
Can you explain me please?

I built my own form, now i don't know if work it, this use a two models in a single form. But, i don't know how can i built a own wagtail form or integrate my form in a wagtail page.

I have this two models:
#Afiliados
class Affiliates(models.Model):
    #type_person = models.CharField(max_length=255, choices=AFFILIATION_PERSON_TYPE)
    name = models.CharField("Nombre Solicitante", max_length=255, )
    logo
= models.ForeignKey(
       
'wagtailimages.Image',
       
null=True,
        blank
=True,
        on_delete
=models.SET_NULL,
        related_name
='logo',
   
)
    dni
= models.IntegerField("Documento de Identificación", max_length=12, help_text="Para NIT omitir la '-'. ")
    adress
= models.CharField("Dirección", max_length=255, )
    country
= models.CharField("País", max_length=255, )
    city
= models.CharField("Ciudad", max_length=255, )
    tel
= models.IntegerField("Teléfono", max_length=10,)
    e_mail
= models.EmailField("Correo Electrónico")
    web
= models.URLField("Sitio Web", max_length=255, null=True, blank=True, )
    fax
= models.IntegerField(max_length=7, null=True, blank=True,)
    attorney_name
= models.CharField("Representante Legal", max_length=255, )
    position
= models.CharField("Cargo", max_length=255, )
    staff
= models.IntegerField("Número de Empleados", max_length=4, null=True, blank=True,)
    interest
= models.CharField("Interéses de Afiliación", choices=INTEREST_AREAS, max_length=255, )
    cause
= models.CharField("Razón Social", max_length=255, )
    economic_sector
= models.CharField("Sector Económico", max_length=255, )
    economic_activity
= models.CharField("Actividad Económica", choices=ECONOMIC_ACTIVITY, max_length=255, null=True, blank=True, )
    other_interes
= models.CharField("Otro", max_length=255,blank=True, null=True, )

   
class Meta:
        #description = 'Modelo Afiliado.'
        verbose_name = "Afiliado"

    def __str__(self):
        return self.name

#Afiliacion
class Affilliation(models.Model):
    person = models.ForeignKey(Person, verbose_name="Tipo de Persona", related_name="person")
    affiliation
= ChainedForeignKey(
       
MemberShip,
        chained_field
="person",
        chained_model_field
="type_person",
        show_all
=False,
        auto_choose
=True,
        verbose_name
='Membresía',
       
#related_name='affiliation'
    )
    affiliates
= models.ForeignKey(Affiliates,  verbose_name="Afiliado", related_name="affiliate")
    date_prein
= models.DateField("Fecha de Inscripción", auto_now_add=True,)
    date_in
= models.DateField("Fecha de Aceptación",blank=True, null=True,)
    date_renew
= models.DateField("Fecha de Renovación", blank=True, null=True, )
   
#date_out = models.DateField(verbose_name='Fecha de Expiración', null=True, blank=True, )
    #is_renew = models.BooleanField(verbose_name='Renovado', help_text="Ha renovado afiliación.", blank=True, null=True, )
    is_active = models.BooleanField(verbose_name='Activo', help_text="Está activo?", default=False, )

   
class Meta:
         #description = "Modelo Afiliacion."
        verbose_name = "Afiliación"
        verbose_name_plural = 'Afiliaciones'

    def __str__(self):
        return '%s, %s' % (self.affiliation, self.affiliates)

The form is made for Affiliaton model, but, this need save the affiliation and afiliates fields both, the idea is can register a affiliate and make his affiliation in the same time.

I think that this is not easy, and i don't know if my own form works. This is the code, for now:
from django import forms
from .models import *

from wagtail.wagtailimages.forms import WagtailImageField

from smart_selects import form_fields, widgets



class AffilliationForm(forms.ModelForm):
    def __init__(self, instance=None, *args, **kwargs):
        _fields = (
       
'name', 'logo', 'dni', 'adress', 'country', 'city', 'tel', 'fax', 'e_mail', 'web', 'attorney_name', 'position',
       
'staff', 'interest', 'cause', 'economic_sector', 'economic_activity', 'other_interes', )
        _initial
= forms.model_to_dict(instance.affiliates) if instance is not None else{}
       
super(AffilliationForm, self).__init__(initial=_initial, instance=instance, *args, **kwargs)
       
self.fields.update(forms.fields_for_model(Affiliates, _fields))


   
class Meta:
        model = Affilliation
        fields
= ['person', 'affiliation', 'date_prein', ]
        exclude
= ('affiliates', )
        widgets
= {
           
'person': form_fields.ChainedModelChoiceField(widget=widgets.ChainedSelect(attrs={'class':'form-control'})),
           
'affiliation': form_fields.ChainedModelChoiceField(widget=widgets.ChainedSelect(attrs={'class':'form-control'})),
           
'name': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'logo': WagtailImageField(widget=forms.FileInput()),
           
'dni': forms.IntegerField(widget=forms.NumberInput(attrs={'class': 'form-control'})),
           
'adress': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'country': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'city': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'tel': forms.IntegerField(widget=forms.NumberInput(attrs={'class': 'form-control'})),
           
'fax': forms.IntegerField(widget=forms.NumberInput(attrs={'class': 'form-control'})),
           
'e_mail': forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'})),
           
'web': forms.URLField(widget=forms.URLInput(attrs={'class': 'form-control'})),
           
'attorney_name': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'position': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'staff': forms.IntegerField(widget=forms.NumberInput(attrs={'class': 'form-control'})),
           
'interest': forms.ChoiceField(widget=forms.Select(attrs={'class': 'form-control'}), choices=INTEREST_AREAS),
           
'cause': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'economic_sector': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
           
'economic_activity': forms.ChoiceField(widget=forms.Select(attrs={'class': 'form-control'}), choices=ECONOMIC_ACTIVITY),
           
'other_interes': forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control'})),
       
}

   
def as_div(self):
        "Returns this form rendered as HTML <div>s."
        return self._html_output(
            normal_row
= u'<div class="form-group" %(html_class_attr)s>%(label)s</div> %(field)s%(help_text)s',
            error_row
= u'%s',
            row_ender
= '</div>',
            help_text_html
= u' <span class="help-block">%s</span>',
            errors_on_separate_row
= True)

   
def save(self, *args, **kwargs):
        a = self.instance.affiliates
        a
.name = self.cleaned_data['name']
        a
.logo = self.cleaned_data['logo']
        a
.dni = self.cleaned_data['dni']
        a
.adress = self.cleaned_data['adress']
        a
.country = self.cleaned_data['country']
        a
.city = self.cleaned_data['city']
        a
.tel = self.cleaned_data['tel']
        a
.fax = self.cleaned_data['fax']
        a
.e_mail = self.cleaned_data['e_mail']
        a
.web = self.cleaned_data['web']
        a
.attorney_name = self.cleaned_data['attorney_name']
        a
.position = self.cleaned_data['position']
        a
.staff = self.cleaned_data['staff']
        a
.interest = self.cleaned_data['interest']
        a
.cause = self.cleaned_data['cause']
        a
.economic_sector = self.cleaned_data['economic_sector']
        a
.economic_activity = self.cleaned_data['economic_activity']
        a
.other_interes = self.cleaned_data['other_interes']
        a
.save()
        affiliate
= super(AffilliationForm, self).save(*args, **kwargs)
       
return affiliate

It's some complicate.

I want use a wagtail page for do this register form, i think that is better.

Thank you very much.

El martes, 10 de febrero de 2015, 0:42:57 (UTC-5), YusufSalahAdDin escribió:

Dan Braghis

unread,
Feb 19, 2015, 4:23:48 AM2/19/15
to wag...@googlegroups.com
Hi Yusuf,

If you want to use the built-in Wagtail form, please follow http://docs.wagtail.io/en/stable/core_components/form_builder.html
In essence, you declare your FormPage, then you can create your new form page with selected form elements (from the admin).

As for the save part, do follow the suggestion I provided in my previous reply.

Were you to keep to your current code, just follow the standard Django method of creating of saving object. (e.g. https://docs.djangoproject.com/en/1.7/ref/models/instances/#creating-objects)

Best,
Dan

YusufSalahAdDin

unread,
Feb 20, 2015, 11:14:12 PM2/20/15
to wag...@googlegroups.com
Ok, can you give me an example for use wagtail form builder? i'm so slow, i don't understand the work flow,
Thank you.
...

YusufSalahAdDin

unread,
Feb 22, 2015, 10:00:17 PM2/22/15
to wag...@googlegroups.com
Please, can you give me any example?


El jueves, 19 de febrero de 2015, 4:23:48 (UTC-5), Dan Braghis escribió:
...

Matthew Westcott

unread,
Feb 23, 2015, 4:30:47 AM2/23/15
to wag...@googlegroups.com
Have you tried the example code on http://docs.wagtail.io/en/stable/core_components/form_builder.html ?

- Matt
> --
> You received this message because you are subscribed to the Google Groups "Wagtail" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to wagtail+u...@googlegroups.com.
> To post to this group, send email to wag...@googlegroups.com.
> Visit this group at http://groups.google.com/group/wagtail.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/wagtail/8a0c6a54-6545-448f-83fb-6c3770019e28%40googlegroups.com.

YusufSalahAdDin

unread,
Feb 24, 2015, 10:25:06 AM2/24/15
to wag...@googlegroups.com
Yes, i use this but, i still don't understand you.

How can i extends AbstactEmailForm with my own model? Please, other example.

YusufSalahAdDin

unread,
Feb 25, 2015, 10:37:42 PM2/25/15
to wag...@googlegroups.com
Ok, i have this:

#Página de registro de afiliados
class FormField(AbstractFormField):
    page = ParentalKey('RegisterFormPage', related_name='form_fields')

class RegisterFormPage(AbstractEmailForm):
    intro = RichTextField(blank=True)
    thank_you_text
= RichTextField(blank=True)

   
class Meta:
        verbose_name_plural = 'Páginas de Inscripción de Afiliado'
        verbose_name = 'Página de Inscripción de Afiliado'

RegisterFormPage.content_panels = [
   
FieldPanel('title', classname="full title"),
   
FieldPanel('intro', classname="full"),
   
InlinePanel(RegisterFormPage, 'form_fields', label="Campos de Formulario"),
   
FieldPanel('thank_you_text', classname="full"),
   
MultiFieldPanel([
       
FieldPanel('to_address', classname="full"),
       
FieldPanel('from_address', classname="full"),
       
FieldPanel('subject', classname="full"),
   
], "Email")
]

But, i don't understand how related my two models with this FormPage. Dan Braghis say me that i can build the form field with the admin fields but i don't understand what i have do now. Can you help me?



El lunes, 23 de febrero de 2015, 4:30:47 (UTC-5), Matthew Westcott escribió:

YusufSalahAdDin

unread,
Mar 1, 2015, 9:13:14 PM3/1/15
to wag...@googlegroups.com
Guys????


El lunes, 23 de febrero de 2015, 4:30:47 (UTC-5), Matthew Westcott escribió:

YusufSalahAdDin

unread,
Jan 21, 2016, 11:48:54 PM1/21/16
to Wagtail support
Ok guys, until now i couldn't do anything.

My first idea was use form_sets for put two models in a single form and the pass to FormPage as form_fields, but reading again your answers i not shure about this.

So, do you say me that create a new FormPage, some like AffiliationFormPage, seems like FormPage; then, in wagtail admin i create a Form with the same fields that models. In AffiliationFormPage i have overwritte process_form_submission function for include a AffiliationForm Client for the form and create a new form object for save the field. Right?


So, i have a few questions, how can i to put fields for foreing key? Affiliate model have a Affiliation field that is a Foreign Key to Affiliation Model.
Then, how can i get this model and save this field with create function?


And, my first idea was wrong?


Thanks for your help man!


El martes, 10 de febrero de 2015, 0:42:57 (UTC-5), YusufSalahAdDin escribió:

Matthew Westcott

unread,
Jan 22, 2016, 7:28:24 AM1/22/16
to wag...@googlegroups.com
Hi,
I would definitely recommend using Django forms for this, instead of the wagtailforms module... wagtailforms doesn't handle relations such as foreign keys, and there's no advantage from having the form fields editable within the Wagtail admin, because those fields are determined by your model definition (any changes to the fields will require changes to the code).

I'd suggest building it using plain Django views and forms first, as described in https://docs.djangoproject.com/en/1.9/topics/forms/ - and then convert it to a Wagtail page, by moving the view code into a `serve` method on the page. You might not even need to do the second step - you could leave it as a Django view, if you're happy for it to exist at a fixed URL and you don't need any editable content on the page.

Since this is quite a common request, I've now created an example project that shows how to use Django forms in Wagtail without using the wagtailforms module:
https://github.com/gasman/wagtail-form-example
By following the commit history <https://github.com/gasman/wagtail-form-example/commits/master>, you'll see how to convert a Django view function to a Wagtail page.

Cheers,
- Matt

Daniel

unread,
Jan 22, 2016, 11:46:52 AM1/22/16
to Wagtail support
Hello,

I think that post and the code could deserve a page in the docs ;)

Regards
Message has been deleted

YusufSalahAdDin

unread,
Feb 3, 2016, 10:22:04 PM2/3/16
to Wagtail support
Thank youi guys, you are the best, i'm doing a formset forms for this page, only now i have test it, when i do this i'll tell you about this.


El martes, 10 de febrero de 2015, 0:42:57 (UTC-5), YusufSalahAdDin escribió:

YusufSalahAdDin

unread,
Feb 14, 2016, 1:28:52 AM2/14/16
to Wagtail support
And yes!, it works!!!

But, doesn't send me to the landing_page :'(

Why?


El martes, 10 de febrero de 2015, 0:42:57 (UTC-5), YusufSalahAdDin escribió:

Cody Django

unread,
Feb 14, 2016, 1:47:35 AM2/14/16
to Wagtail support
If you've implemented your code in the exact same way it's done in the github example, it's because you're returning a rendered thank you page:


If you'd rather redirect the user to the landing page you can return a redirect instead:

YusufSalahAdDin

unread,
Feb 14, 2016, 2:30:43 AM2/14/16
to Wagtail support
I do the same that github repository:

class RegisterFormPage(AbstractEmailForm, TranslationMixin):
    intro = RichTextField(_('Introduction'), blank=True)
    thank_you_text
= RichTextField(_("Thank you text"), blank=True)

   
class Meta:
        verbose_name_plural = _("Affiliate registration's pages")
        verbose_name
= _("Affiliate registration's page")

   
"""
    def process_form_submission(self, form):
        super(RegisterFormPage, self).process_form_submission(form)
    """

    def serve(self, request):
        from .forms import AffiliatesForm, AffiliationInlineForm

       
AffiliationFormSet = inlineformset_factory(
               
Affiliates,
               
Affiliation,
               
form=AffiliationInlineForm,
               
fields=['person', 'affiliation', ],
               
extra=1
        )
       
form = AffiliatesForm()
        formset
= AffiliationFormSet()

       
if request.method == 'POST':
            form = AffiliatesForm(request.POST)
            formset
= AffiliationFormSet(request.POST)

           
if form.is_valid() and formset.is_valid():
                formset = formset.save()
                form
= form.save()

               
return render(request, 'form_page_landing.html', {
                   
'page': self,
                   
'form': form,
                   
'formset': formset
               
})
       
else:
            form = AffiliatesForm()

       
return render(request, 'form_page.html', {
           
'page': self,
           
'form': form,
           
'formset': formset
       
})



RegisterFormPage.content_panels = [
   
FieldPanel('title', classname="full title"),
   
FieldPanel('intro', classname="full"),

   
FieldPanel('thank_you_text', classname="full"),
   
MultiFieldPanel([
       
FieldPanel('to_address', classname="full"),
       
FieldPanel('from_address', classname="full"),
       
FieldPanel('subject', classname="full"),

   
], _('E-mail'))
]

But this doesn't redirect me to the form_landing_page, render me the same page with the same information, but with all saved in the database, when i'll go to see in django-admin, a new model was created.
If i try to save the same form then this edit me the object that was created, doesn't show me any error.

YusufSalahAdDin

unread,
Feb 14, 2016, 3:07:26 AM2/14/16
to Wagtail support
Ok, i think that this is because the form and his form set isn't saved properly, but i don't know what it's the properly form.


El martes, 10 de febrero de 2015, 0:42:57 (UTC-5), YusufSalahAdDin escribió:

YusufSalahAdDin

unread,
Feb 14, 2016, 7:52:18 PM2/14/16
to Wagtail support
Ok, i find other problem: https://github.com/gasman/wagtail-form-example/issues/1
I report this issue in his github repository but was closed, why?

Can anyone help me to solve this problem?


El martes, 10 de febrero de 2015, 0:42:57 (UTC-5), YusufSalahAdDin escribió:

Matthew Westcott

unread,
Feb 15, 2016, 9:52:16 AM2/15/16
to wag...@googlegroups.com
Hi Yusuf,
I closed the issue because I don't provide personal one-to-one tech support for Wagtail. This Google group is the correct place for support requests, as there's a wider group of people available to provide help, not just myself. I'm happy to help out here because I'm keen to help the Wagtail community to grow, and in turn that will lead to more people providing support here. Posting on Github means that it will be seen mainly by the core Wagtail developers - it won't get you an answer any faster, and the time spent dealing with support requests there means that we have less time available to develop Wagtail further.

To answer your question - from the code you posted earlier:

class RegisterFormPage(AbstractEmailForm, TranslationMixin):

You don't need to inherit from AbstractEmailForm here, as you aren't using any behaviour from wagtailforms any more. You should just inherit from the basic Page model instead:

class RegisterFormPage(Page, TranslationMixin):

Cheers,
- Matt
Reply all
Reply to author
Forward
0 new messages