Question

On my form, I have two buttons that I use for submitting the form. One button deletes selected files (presented in a table, one checkbox to an object) and the other selects them for processing.

When the files are selected on deletion, no validation is necessary (beyond checking that at least one file has been selected). However, for processing I need to make sure that there is exactly one file of a certain extension. Basically, I need different validation processes based on which button the user clicked.

How can I best do this? I know I can perform validation in the view, but I would much prefer validating this inside the form, since it's cleaner.

Here's the forms in question:

class ButtonWidget(object):
    """A widget to conveniently display buttons.
    """
    def __call__(self, field, **kwargs):
        if field.name is not None:
            kwargs.setdefault('name', field.name)
        if field.value is not None:
            kwargs.setdefault('value', field.value)
        kwargs.setdefault('type', "submit")
        return HTMLString('<button %s>%s</button>' % (
            html_params(**kwargs),
            escape(field._value())
            ))

class ButtonField(Field):
    """A field to conveniently use buttons in flask forms.
    """
    widget = ButtonWidget()

    def __init__(self, text=None, name=None, value=None, **kwargs):
        super(ButtonField, self).__init__(**kwargs)
        self.text = text
        self.value = value
        if name is not None:
            self.name = name

    def _value(self):
        return str(self.text)

class MultiCheckboxField(SelectMultipleField):
    """
    A multiple-select, except displays a list of checkboxes.

    Iterating the field will produce subfields, allowing custom rendering of
    the enclosed checkbox fields.
    """
    widget = ListWidget(prefix_label=False)
    option_widget = CheckboxInput()

class ProcessForm(Form, HiddenSubmitted):
    """
    Allows the user to select which objects should be
    processed/deleted/whatever.
    """

    PROCESS = "0"
    DELETE = "-1"

    files = MultiCheckboxField("Select", coerce=int, validators=[
        Required()
        ]) # This is the list of the files available for selection
    process_button = ButtonField("Process", name="action", value=PROCESS)
    delete_button = ButtonField("Delete",  name="action", value=DELETE)

    def validate_files(form, field):
        # How do I check which button was clicked here?
        pass
Was it helpful?

Solution

The key thing to note about buttons in HTML is that only the button that was pressed sends its data back to the server. So you can just check if the button's data field is set using if form.process_button.data an things will work in the general case.

In your particular case, since both of your buttons pull their data from the same underlying parameter name (action) you will need to check that the data in one of your button fields is what you would expect:

def validate_files(form, field):
    # If the ButtonFields used different names then this would just be
    # if form.process_button.data:
    if form.process_button.data == ProcessForm.PROCESS:
        # Then the user clicked process_button
    else:
        # The user clicked delete_button
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top