简体   繁体   中英

How to use WTForms FormField with additional parameters?

I've got form LimitForm with parameter resource

class LimitForm(FlaskForm):
        def __init__(self, resource: Resource, *args, **kwargs):
           super(LimitForm, self).__init__(*args, **kwargs)
           self.period.choices = Period.choices()

I would like to use this form in other form as field through FormField. Like a

class LimitsForm(FlaskForm)
   limits = FieldList(FormField(LimitForm))

but this code raises exception TypeError: __init__() missing 1 required positional argument: 'resource'

How can I pass resource to LimitForm from LimitsForm?

Thanks

You may find is easier to perform some additional logic after the normal initialization of the enclosing class, eg implement you own LimitsForm.__init__() with special logic at the end. Otherwise, you will likely have to subclass FieldList and FormField and override their process methods and life will become complicated for you if all you need to do is a simple extra step for one use case!

For example, I have a case where I want to do something similar to what you request and pass some special kwargs through a FormField . Flask-WTF does not seem to do this by default. In this case I am using a QuerySelectField that I want to pass some special filter through to when I call SQLAlchemy.

In my controller, the call to this is like

form = CampaignForm(obj=campaign, studio=campaign.studio)

Here, the studio is part of a special filter and is only known at run time. However, this studio kwarg does not make it through the nested FormField .

Because I'd have to extend and rewire core logic in Flask-WTF to pass this kwarg through the FormField and into GatingExtraForm , my solution to this problem is to do this instead:

class GatingExtraForm(FlaskForm):
    class Meta:
        # we do not need CSRF in sub-forms
        csrf = False

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.set_query(studio=kwargs.get('studio'))

    # when this form is nested in a FormField, the studio kwarg may not be passed to __init__, 
    # therefore we make this method available for some post-initialization.
    def set_query(self, studio=None):
        self.gating_campaign.query = db.query(InAppCampaign).filter(InAppCampaign.active)

        if studio:
            self.gating_campaign.query = self.gating_campaign.query.filter(InAppCampaign.studio == studio)

        self.gating_campaign.query = self.gating_campaign.query.order_by(InAppCampaign.name)

    gating_campaign = QuerySelectField(
        "Gating Campaign",
        get_label='name',
        allow_blank=False,
        validators=[validators.Optional()]
    )
    # additional fields here....

class CampaignForm(FlaskForm):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # because there is no naive way to pass kwargs through on FormField init, 
        # just do some post init special processing
        self.gating_extra.form.set_query(studio=kwargs.get('studio'))

    # additional fields here....
    gating_extra = FormField(GatingExtraForm)

This is a bit of a hack, I'll admit, but sometimes it's a reasonable trade-off for rare use-cases. If it turns out to be a common pattern, then you can go deeper into extending Flask-WTF.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM