Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support passing extra fields to the Form constructor #736

Open
benthorner opened this issue Apr 6, 2022 · 0 comments
Open

Support passing extra fields to the Form constructor #736

benthorner opened this issue Apr 6, 2022 · 0 comments
Labels
enhancement New feature, or existing feature improvement

Comments

@benthorner
Copy link

benthorner commented Apr 6, 2022

Expected Behavior

We have some data like the following:

[
  {'id': 'item1', 'percentage': 20},
  {'id': 'item2', 'percentage': 50},
  {'id': 'item3', 'percentage': 30},
]

We want to make a form with an input for each item so that we can change all the percentages in one go and check they still add up to 100%. The number of items will change over time based on what's in our database, so we can't hard-code them as class-level attributes and need to specify the fields dynamically instead.

In theory we could do this with the BaseForm class, passing an unbound field for each input in the constructor. However, this isn't possible for us in practice as we're using the FlaskForm class from flask_wtf, which inherits from Form. The Form class locks the set of fields to the class-level attributes discovered by its metaclass.

Ideally we would do this:

class DynamicFieldForm(Form): 
  # item_1 = InputField(item_1_id)  # can't do this
  # code to do validation, etc.
  pass

form = DynamicFieldForm(
  extra_fields=[
    InputField(item['id']) for item in items
  ],
  data={
    item['id']: item['percentage'] for item in items
  }
)

Actual Behavior

It's possible to pass fields in the constructor with this hack:

# toy example without validation
class DynamicFieldForm(Form):
    def __init__(self, items):
        self._unbound_fields = [
          (item['id'], InputField(item['id'])
          for item in items
        ]

        super().__init__(data={
            item['id']: item['percentage'] for item in items
        })

...

# get data for an item later on
getattr(form, item['id']).data

Using the internal _unbound_fields attribute isn't great as it's not part of the public interface and might break in future versions. Would it be possible to expose it in the constructor for the Form class?

Environment

  • Python version: 3.9
  • wtforms version: 3.0.1
benthorner pushed a commit to alphagov/notifications-admin that referenced this issue Apr 6, 2022
This replaces the slider with an integer input for each provider.
Unfortunately showing a variable number of inputs isn't easy to
achieve in WTForms [^1], but we think this is the least worst way
to do it vs e.g. not using WTForms at all.

[^1]: pallets-eco/wtforms#736
benthorner pushed a commit to alphagov/notifications-admin that referenced this issue Apr 7, 2022
This replaces the slider with an integer input for each provider.
Unfortunately showing a variable number of inputs isn't easy to
achieve in WTForms [^1], but we think this is the least worst way
to do it vs e.g. not using WTForms at all.

[^1]: pallets-eco/wtforms#736
benthorner pushed a commit to alphagov/notifications-admin that referenced this issue Apr 7, 2022
This replaces the slider with an integer input for each provider.
Unfortunately showing a variable number of inputs isn't easy to
achieve in WTForms [^1], but we think this is the least worst way
to do it vs e.g. not using WTForms at all.

[^1]: pallets-eco/wtforms#736
benthorner pushed a commit to alphagov/notifications-admin that referenced this issue Apr 7, 2022
This replaces the slider with an integer input for each provider.
Unfortunately showing a variable number of inputs isn't easy to
achieve in WTForms [^1], but we think this is the least worst way
to do it vs e.g. not using WTForms at all.

[^1]: pallets-eco/wtforms#736
@azmeuk azmeuk added the enhancement New feature, or existing feature improvement label Jul 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature, or existing feature improvement
Development

No branches or pull requests

2 participants