jcuot
jcuot

Reputation: 951

Wagtail form builder with additional constant fields

I have created a quiz with wagtail form builder, but I need the form to contain some fields which are constant. For example, I have the following:

  1. Name
  2. Email
  3. Employee id
  4. [form builder fields]

How do I integrate fields [1-3] in the form builder to show up on all quizzes?

Upvotes: 1

Views: 883

Answers (1)

LB Ben Johnston
LB Ben Johnston

Reputation: 5196

A simple way to do this is to override the get_form_fields method on your FormPage model.

This method simply returns a query for all stored FormFields on the FormPage model. We can add instances of FormField as needed and this will make the fields available in the form (view). They will also be available in form reports and emails.

1 - Override get_form_fields in your FormPage class.

In myapp/models.py wherever you have defined your FormPage model, add the following:

    class FormPage(AbstractEmailForm):

        # ...additional FormPage fiels and content_panels

        def get_form_fields(self):
            # get form_fields as defined by the super class & convert to list
            # otherwise returns queryset
            fields = list(super(FormPage, self).get_form_fields())

            # append instances of FormField - not actually stored in the db
            # field_type can only be one of the following:
            # 'singleline', 'multiline', 'email', 'number', 'url', 'checkbox',
            # 'checkboxes', 'dropdown', 'multiselect', 'radio', 'date',
            # 'datetime', 'hidden'
            # Important: Label MUST be unique in each form

            # `insert(0` will prepend these items, so here ID will be first

            fields.insert(0, FormField(
                label='Employee Name',
                field_type='singleline',
                required=False,
                help_text="Employee's Name"))

            fields.insert(0, FormField(
                label='Employee Email',
                field_type='email',
                required=False,
                help_text="Employee's Email"))

            fields.insert(0, FormField(
                label='Employee ID',
                field_type='number',
                required=False,
                help_text="Employee's ID"))

            return fields

Note: When creating our FormField instances, these are not stored in the database, but their responses will be. You should provide the attributes label, field_type, required and help_text.

2 - Ensure there are no label conflicts on existing Forms

If the form label 'Employee ID' is used already in a form - not sure what will happen but it will likely break things so check you do not have conflicts in existing form pages.

Note: If the label is the same, you will not loose your data from previous submissions. All data is stored for past submissions even if you change the FormFields in use.

3 - Override the label field on FormField with some validation

In myapp/models.py wherever you have defined your FormField model, add the following:

from django.core.exceptions import ValidationError

# ... other imports and then models

RESERVED_LABELS = ['Employee Name', 'Employee Email', 'Employee ID']

def validate_label(value):
    if value in RESERVED_LABELS:
        raise ValidationError("'%s' is reserved." % value)


class FormField(AbstractFormField):
    # page = ...
    # redefine 'label' field so we can ensure there will be no conflicts with constant fields
    label = models.CharField(
        verbose_name='label',
        max_length=255,
        help_text='The label of the form field, cannot be one of the following: %s.'
        % ', '.join(RESERVED_LABELS),
        validators=[validate_label]
    )

RESERVED_VALUES should match the labels used in your FormPage model.

This creates a simple Django Field Validator to check that you will not have conflicting labels. It also adds some nice help text so users do not get confused.

4 - Migrate

You should also do a migrations as you have now changed the label field on the FormField model.

Upvotes: 3

Related Questions