【问题标题】:Custom attributes for Flask WTFormsFlask WTForms 的自定义属性
【发布时间】:2013-12-24 18:11:33
【问题描述】:

我在 Flask 和 AngularJS 上开发网站。我需要使用 AngularJS 发送带有 AJAX 的表单,但它需要输入字段的自定义属性。例如我在 Jinja2 模板中有一个表单:

<form method="post" action="/">
    {{ form.hidden_tag() }}
    {{ form.name(placeholder="Name") }}
</form>

那么我怎样才能从 AngularJS 中添加一个属性让我为我的“名称”字段说“ng-model”?

感谢您的帮助!

【问题讨论】:

  • 人力资源管理;我认为 Jinja2 不支持传入 **{...} 关键字飞溅,所以 form.name(placeholder="Name", **{'ng-model': 'value'}) 不起作用。我认为
  • 我找到了一个使用 WTForms 自定义小部件的解决方案。它有一个在文档中添加“类”属性的示例。
  • 是的,我在这里使用自定义小部件来解决 Jinja2 中的限制。

标签: javascript python angularjs flask wtforms


【解决方案1】:

Python 标识符中不允许使用破折号,并且只有 Python 标识符可以用作调用中的 keyword_argument=value 对。

但是你有几个选项可以解决这个问题;您可以在**kwargs 映射中传递ng- 前缀选项,让您用于表单的Meta 类将_ 转换为- 以获取ng_ 属性,或者使用自定义小部件来执行同样的翻译。

传入 **kwargs 映射

使用**kwargs,您可以传入不是 Python 标识符的参数,只要它们是字符串。使用它来呈现您的表单字段:

{{ form.name(placeholder="Name", **{'ng-model': 'NameModel'}) }}

您可以将相同的信息放在字段定义上的render_kw 映射中:

class MyForm(Form):
    name = StringField(u'Full Name', render_kw={'ng-model': 'NameModel'})

每次渲染字段时都会使用它; render_kw 会添加到渲染时传入的任何参数中,因此:

{{ form.name(placeholder="Name") }}

将同时渲染 placeholderng-model 属性。

子类 Meta 并在您的表单中使用它

从 WTForm 2.0 开始,Meta class you attach to your form 实际上被要求使用Meta.render_field() hook 呈现字段:

import wtform.meta

class AngularJSMeta:
    def render_field(self, field, render_kw):
        ng_keys = [key for key in render_kw if key.startswith('ng_')]
        for key in ng_keys:
            render_kw['ng-' + key[3:]] = render_kw.pop(key)
        # WTForm dynamically constructs a Meta class from all Meta's on the
        # form MRO, so we can use super() here:
        return super(AngularJSMeta, self).render_field(field, render_kw)

直接在您的表单上使用它:

class MyForm(Form):
    Meta = AngularJSMeta

    name = StringField(u'Full Name')

或子类化Form 类:

class BaseAngularJSForm(Form):
    Meta = AngularJSMeta

并将其用作所有表单的基础:

class MyForm(BaseAngularJSForm):
    name = StringField(u'Full Name')

现在您可以使用这是您的模板:

{{ form.name(placeholder="Name", ng_model='NameModel') }}

子类小部件

您可以使用以下方式子类化您选择的小部件:

class AngularJSMixin(object):
    def __call__(self, field, **kwargs):
        for key in list(kwargs):
            if key.startswith('ng_'):
                kwargs['ng-' + key[3:]] = kwargs.pop(key)
        return super(AngularJSMixin, self).__call__(field, **kwargs)

class AngularJSTextInput(AngularJSMixin, TextInput):
    pass

这会将任何以ng_ 开头的关键字参数转换为以ng- 开头的关键字参数,从而确保可以添加正确的HTML 属性。 AngularJSMixin 可以与任何小部件类一起使用。

将此作为widget 属性用于您的字段:

class MyForm(Form):
    name = StringField(u'Full Name', widget=AngularJSTextInput())

在渲染模板时,您可以再次使用ng_model

{{ form.name(placeholder="Name", ng_model='NameModel') }}

在所有情况下,属性将在呈现的 HTML 中添加为 placeholder="Name" ng-model="NameModel"

<input id="name" name="name" ng-model="NameModel" placeholder="Name" type="text" value="">

【讨论】:

  • 如何在 jinja2 宏中调用这些?只是field.ng-model 对我不起作用。我去了{% if field.ng-model %} {{ field.ng-model }} {% endif %},但它不起作用
  • @TobiasKolb:您正在尝试访问一个属性,并且属性名称遵循相同的规则; - 是 Python 代码中的减法运算符,因此不能作为标识符的一部分。即便如此,ng-model不是字段的属性。如果您使用render_kw={...} 选项为您的字段定义ng-model 属性值,那么您可以使用field.render_kw['ng-model'] 访问该值。
  • @TobiasKolb:(并且很抱歉现在才发现您的评论,事后 6 个月,当时它一定已经引起了我的注意)。
【解决方案2】:
{{ form.username(placeholder='your name', size=20, **{'ng-model':'hello', 'class':'hello'}) }}

我觉得更好

【讨论】:

  • 就像一个魅力!谢谢!如果有人想知道,它还会打印所有其他键和值。
  • 在 Flask 1.x 中仍然可以很好地工作,我正在使用它为客户端验证添加一些自定义属性。
猜你喜欢
  • 2018-09-03
  • 1970-01-01
  • 2021-08-16
  • 1970-01-01
  • 1970-01-01
  • 2022-12-20
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多