How do I bind an flask-wtform UnboundField?

无人久伴 提交于 2020-05-30 19:15:53

问题


I am creating an app to post products to a marketplace. Each product category on this marketplace has a different form for product attributes, for example if it's electronic there are fields for voltage, model number... I get this information via json through the marketplace server. First the user has to write the name of the product and it's main category and the marketplace server predicts their own category and returns to me it's attributes. Here's an example of the response:

{
"id": "MODEL",
"name": "Modelo",
"tags": {
  "hidden": true
},
{
"id": "PACKAGE_LENGTH",
"name": "Comprimento da embalagem",
"tags": {
  "hidden": true,
  "read_only": true,
  "variation_attribute": true
},
"hierarchy": "ITEM",
"relevance": 2,
"value_type": "number_unit",
"value_max_length": 255,
"allowed_units": [
  {
    "id": "km",
    "name": "km"
  },
  {
    "id": "polegadas",
    "name": "polegadas"
  },
  {
    "id": "ft",
    "name": "ft"
  },
  {
    "id": "mm",
    "name": "mm"
  },
  {
    "id": "m",
    "name": "m"
  },
  {
    "id": "\"",
    "name": "\""
  },
  {
    "id": "in",
    "name": "in"
  },
  {
    "id": "cm",
    "name": "cm"
  }
],
"default_unit": "cm",
"attribute_group_id": "OTHERS",
"attribute_group_name": "Outros"
}

So far so good.

Now I need to create a dynamic form to be able to add/edit those fields because each category has a different type of attribute, and different amount. Each field needs to have an ID, a type (could be string only, or numbers only) an label, and a max length and if its of value_type number_unit needs a SelectField with the given units.

I'm getting this information in a view, and at the same view I create a subclass of a FlaskForm, where I create a list of fields based on the type of the attribute.

   class DynamicForm(PostProductForm):
        loaded_attr = json.loads(meli.get(f"/categories/{category}/attributes").content.decode('utf-8'))
        attribute_fields = []
        for attribute in loaded_attr:
            tags = attribute.get('tags')
            if not tags.get('read_only'):
                if attribute.get('value_type') == 'number_unit':
                    attribute_fields.append(IntegerField(
                        attribute['name'], validators=[Length(min=0, max=attribute['value_max_length'])]))
                    allowed_units = [(unit['id'], unit['name']) for unit in attribute['allowed_units']]
                    attribute_fields.append(SelectField('Unidade', choices=allowed_units))

                elif attribute['value_type'] == 'string':
                    attribute_fields.append(StringField(
                        attribute['name'], validators=[Length(min=0, max=attribute['value_max_length'])]))

                elif attribute['value_type'] == 'number':
                    attribute_fields.append(IntegerField(
                        attribute['name'],
                        validators=[Length(min=0, max=attribute['value_max_length'])]))
                elif attribute['value_type'] == 'boolean':
                    attribute_fields.append(BooleanField(attribute['name']))

But this creates a bunch of UnboundFields. If I try to render only each field repr it shows me this:

<UnboundField(StringField, ('SKU ',), {'validators': [<wtforms.validators.Length object at 0x04DFBEF0>]})>

If I try to render the field it gives me an exception:

TypeError: 'UnboundField' object is not callable

I am looping through the list inside the template.

    {% for attribute in form.attribute_fields %}
    <div class="form-group blocked">
        {{ attribute() }}
    </div>
    {% endfor %}

How do I bind an UnboundField?


回答1:


To create a dynamic form with wtforms use the following template

def DynamicForm(*args, **kwargs):
    class StaticForm(FlaskForm):
        pass

    if args[0] == True:
        StaticForm.class_attrib1 = StringField(...)
    else:
        StaticForm.class_attrib2 = StringField(...)

    return StaticForm()

This establishes a StaticForm within the local scope of the function, attaches all of the relevant items based on programming logic from the function arguments and returns an instantiated form:

form = DynamicForm(True)
# form has attribute: class_attrib1

This is explained in the docs somewhere, but I cant find the link right now



来源:https://stackoverflow.com/questions/51599936/how-do-i-bind-an-flask-wtform-unboundfield

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!