다운로드 및 설치
WTForms를 설치하는 가장 쉬운 방법은 easy_install 및 pip를 사용하는 것입니다.
easy_install WTForms # or pip install WTForms
PyPI에서 WTForms를 수동으로 다운로드하고 python setup.py install을 실행할 수 있습니다.
모든 위험을 감수하고 싶은 사람이라면 Git에서 최신 버전을 실행하면 됩니다. 최신 변경 세트 패키지 버전을 가져오거나 프로젝트 홈페이지로 이동하여 코드 저장소를 복제할 수 있습니다.
주요 개념
Forms 클래스는 WTForms의 핵심 컨테이너입니다. 필드(필드) 모음 및 필드는 양식의 사전 양식 또는 속성 양식을 통해 액세스할 수 있습니다.
필드(필드)는 가장 무거운 작업을 수행하며 각 필드(필드)는 데이터 유형을 나타내며 필드 작업은 양식을 강제합니다. 예를 들어, InputRequired 및 StringField는 포함된 데이터 외에도 레이블, 설명 및 유효성 검사 오류 목록과 같은 많은 유용한 속성을 나타냅니다. 🎜> 각 필드에는 위젯(부분) 인스턴스가 있습니다. 위젯의 작업은 필드의 HTML 표현을 렌더링하는 것입니다. 각 필드는 위젯 인스턴스를 지정할 수 있지만 기본적으로 일부 필드는 간단하고 편리합니다. 기본 위젯(위젯)인 TextAreaField는 TextArea의
StringField
이므로 유효성 검사 규칙을 지정하기 위해 필드에는 유효성 검사기 목록이 포함됩니다.
시작
자 본론으로 들어가서 첫 번째 A 양식을 정의하세요::
from wtforms import Form, BooleanField, StringField, validators class RegistrationForm(Form): username = StringField('Username', [validators.Length(min=4, max=25)]) email = StringField('Email Address', [validators.Length(min=6, max=35)]) accept_rules = BooleanField('I accept the site rules', [validators.InputRequired()])
class ProfileForm(Form): birthday = DateTimeField('Your Birthday', format='%m/%d/%y') signature = TextAreaField('Forum Signature') class AdminProfileForm(ProfileForm): username = StringField('Username', [validators.Length(max=40)]) level = IntegerField('User Level', [validators.NumberRange(min=0, max=10)])
양식 사용
양식을 사용하는 것은 인스턴스화만큼 쉽습니다. 이전에 정의된 RegistrationForm을 사용하는 다음 Django 스타일 보기 기능을 고려하세요. class::
def register(request): form = RegistrationForm(request.POST) if request.method == 'POST' and form.validate(): user = User() user.username = form.username.data user.email = form.email.data user.save() redirect('register') return render_response('register.html', form=form)
기존 개체 편집
이전 등록 예제에서는 입력을 받고 새 항목에 대한 유효성을 검사하는 방법을 보여줬습니다. 하지만 기존 개체를 편집하려면 어떻게 해야 할까요? 매우 간단합니다::
def edit_profile(request): user = request.current_user form = ProfileForm(request.POST, user) if request.method == 'POST' and form.validate(): form.populate_obj(user) user.save() redirect('edit_profile') return render_response('edit_profile.html', form=form)
콘솔에서 탐색
WTForms Forms는 매우 간단한 컨테이너 개체로, 아마도 양식에서 어떤 것이 적합한지 알아내는 가장 쉬운 방법은 재생을 제어하는 것입니다. 타이중에서 양식 사용:
>>> from wtforms import Form, StringField, validators >>> class UsernameForm(Form): ... username = StringField('Username', [validators.Length(min=5)], default=u'test') ... >>> form = UsernameForm() >>> form['username'] <wtforms.fields.StringField object at 0x827eccc> >>> form.username.data u'test' >>> form.validate() False >>> form.errors {'username': [u'Field must be at least 5 characters long.']}
>>> form2 = UsernameForm(username=u'Robert') >>> form2.data {'username': u'Robert'} >>> form2.validate() True
양식이 데이터를 가져오는 방법
처음 두 매개변수(formdata 및 obj)를 사용하여 데이터를 제공하는 것 외에도 키워드 매개변수를 전달하여 양식을 채울 수 있습니다. formdata, obj, prefix와 같은 일부 매개변수 이름은 예약되어 있습니다.
formdata는 obj보다 우선순위가 높고 obj는 키워드 매개변수보다 우선순위가 높습니다. 예:
def change_username(request): user = request.current_user form = ChangeUsernameForm(request.POST, user, username='silly') if request.method == 'POST' and form.validate(): user.username = form.username.data user.save() return redirect('change_username') return render_response('change_username.html', form=form)
양식 입력이 없으면, 그런 다음 다음 순서가 시도됩니다.
WTForms中的验证器(Validators)为域(field)提供一套验证器, 当包含域的表单进行验证时运行. 你提供验证器可通过域构造函数的第二个参数validators:
class ChangeEmailForm(Form): email = StringField('Email', [validators.Length(min=6, max=120), validators.Email()])
你可以为一个域提供任意数量的验证器. 通常, 你会想要提供一个定制的错误消息:
class ChangeEmailForm(Form): email = StringField('Email', [ validators.Length(min=6, message=_(u'Little short for an email address?')), validators.Email(message=_(u'That\'s not a valid email address.')) ])
这通常更好地提供你自己的消息, 作为必要的默认消息是通用的. 这也是提供本地化错误消息的方法.
对于内置的验证器的列表, 查阅 Validators.
渲染域
渲染域和强制它为字符串一样简单:
>>> from wtforms import Form, StringField >>> class SimpleForm(Form): ... content = StringField('content') ... >>> form = SimpleForm(content='foobar') >>> str(form.content) '<input id="content" name="content" type="text" value="foobar" />' >>> unicode(form.content) u'<input id="content" name="content" type="text" value="foobar" />'
然而, 渲染域的真正力量来自于它的 __call__() 方法. 调用(calling)域, 你可以提供关键词参数, 它们会在输出中作为HTML属性注入.
>>> form.content(style="width: 200px;", class_="bar") u'<input class="bar" id="content" name="content" style="width: 200px;" type="text" value="foobar" />'
现在, 让我们应用这个力量在 Jinja 模板中渲染表单. 首先, 我们的表单:
class LoginForm(Form): username = StringField('Username') password = PasswordField('Password') form = LoginForm()
然后是模板文件:
<form method="POST" action="/login"> <p>{{ form.username.label }}: {{ form.username(class="css_class") }}</p> <p>{{ form.password.label }}: {{ form.password() }}</p> </form>
相同的, 如果你使用 Django 模板, 当你想要传送关键词参数时, 你可以使用我们在Django扩展中提供的模板标签form_field:
{% load wtforms %} <form method="POST" action="/login"> <p> {{ form.username.label }}: {% form_field form.username class="css_class" %} </p> <p> {{ form.password.label }}: {{ form.password }} </p> </form>
这两个将会输出:
<form method="POST" action="/login"> <p> <label for="username">Username</label>: <input class="css_class" id="username" name="username" type="text" value="" /> </p> <p> <label for="password">Password</label>: <input id="password" name="password" type="password" value="" /> </p> </form>
WTForms是模板引擎不可知的, 同时会和任何允许属性存取、字符串强制(string coercion)、函数调用的引擎共事. 在 Django 模板中, 当你不能传送参数时, 模板标签 form_field 提供便利.
显示错误消息
现在我们的表单拥有一个模板, 让我们增加错误消息::
<form method="POST" action="/login"> <p>{{ form.username.label }}: {{ form.username(class="css_class") }}</p> {% if form.username.errors %} <ul class="errors">{% for error in form.username.errors %}<li>{{ error }}</li>{% endfor %}</ul> {% endif %} <p>{{ form.password.label }}: {{ form.password() }}</p> {% if form.password.errors %} <ul class="errors">{% for error in form.password.errors %}<li>{{ error }}</li>{% endfor %}</ul> {% endif %} </form>
如果你喜欢在顶部显示大串的错误消息, 也很简单:
{% if form.errors %} <ul class="errors"> {% for field_name, field_errors in form.errors|dictsort if field_errors %} {% for error in field_errors %} <li>{{ form[field_name].label }}: {{ error }}</li> {% endfor %} {% endfor %} </ul> {% endif %}
由于错误处理会变成相当冗长的事情, 在你的模板中使用 Jinja 宏(macros, 或者相同意义的) 来减少引用是更好的. (例子)
定制验证器
这有两种方式定制的验证器. 通过定义一个定制的验证器并在域中使用它:
from wtforms.validators import ValidationError def is_42(form, field): if field.data != 42: raise ValidationError('Must be 42') class FourtyTwoForm(Form): num = IntegerField('Number', [is_42])
或者通过提供一个在表单内的特定域(in-form field-specific)的验证器:
class FourtyTwoForm(Form): num = IntegerField('Number') def validate_num(form, field): if field.data != 42: raise ValidationError(u'Must be 42')
编写WTForm扩展示例
class TagListField(Field): widget = TextInput() def _value(self): if self.data: return u', '.join(self.data) else: return u'' def process_formdata(self, valuelist): if valuelist: self.data = [x.strip() for x in valuelist[0].split(',')] else: self.data = []
根据上面的代码,将TagListField中的字符串转为models.py中定义的Tag对象即可:
class TagListField(Field): widget = TextInput() def __init__(self, label=None, validators=None, **kwargs): super(TagListField, self).__init__(label, validators, **kwargs) def _value(self): if self.data: r = u'' for obj in self.data: r += self.obj_to_str(obj) return u'' else: return u'' def process_formdata(self, valuelist): print 'process_formdata..' print valuelist if valuelist: tags = self._remove_duplicates([x.strip() for x in valuelist[0].split(',')]) self.data = [self.str_to_obj(tag) for tag in tags] else: self.data = None def pre_validate(self, form): pass @classmethod def _remove_duplicates(cls, seq): """去重""" d = {} for item in seq: if item.lower() not in d: d[item.lower()] = True yield item @classmethod def str_to_obj(cls, tag): """将字符串转换位obj对象""" tag_obj = Tag.query.filter_by(name=tag).first() if tag_obj is None: tag_obj = Tag(name=tag) return tag_obj @classmethod def obj_to_str(cls, obj): """将对象转换为字符串""" if obj: return obj.name else: return u'' class TagListField(Field): widget = TextInput() def __init__(self, label=None, validators=None, **kwargs): super(TagListField, self).__init__(label, validators, **kwargs) def _value(self): if self.data: r = u'' for obj in self.data: r += self.obj_to_str(obj) return u'' else: return u'' def process_formdata(self, valuelist): print 'process_formdata..' print valuelist if valuelist: tags = self._remove_duplicates([x.strip() for x in valuelist[0].split(',')]) self.data = [self.str_to_obj(tag) for tag in tags] else: self.data = None def pre_validate(self, form): pass @classmethod def _remove_duplicates(cls, seq): """去重""" d = {} for item in seq: if item.lower() not in d: d[item.lower()] = True yield item @classmethod def str_to_obj(cls, tag): """将字符串转换位obj对象""" tag_obj = Tag.query.filter_by(name=tag).first() if tag_obj is None: tag_obj = Tag(name=tag) return tag_obj @classmethod def obj_to_str(cls, obj): """将对象转换为字符串""" if obj: return obj.name else: return u''
主要就是在process_formdata这一步处理表单的数据,将字符串转换为需要的数据。最终就可以在forms.py中这样定义表单了:
... class ArticleForm(Form): """编辑文章表单""" title = StringField(u'标题', validators=[Required()]) category = QuerySelectField(u'分类', query_factory=get_category_factory(['id', 'name']), get_label='name') tags = TagListField(u'标签', validators=[Required()]) content = PageDownField(u'正文', validators=[Required()]) submit = SubmitField(u'发布') ... ... class ArticleForm(Form): """编辑文章表单""" title = StringField(u'标题', validators=[Required()]) category = QuerySelectField(u'分类', query_factory=get_category_factory(['id', 'name']), get_label='name') tags = TagListField(u'标签', validators=[Required()]) content = PageDownField(u'正文', validators=[Required()]) submit = SubmitField(u'发布') ... 在views.py中处理表单就很方便了: def edit_article(): """编辑文章""" form = ArticleForm() if form.validate_on_submit(): article = Article(title=form.title.data, content=form.content.data) article.tags = form.tags.data article.category = form.category.data try: db.session.add(article) db.session.commit() except: db.session.rollback() return render_template('dashboard/edit.html', form=form) def edit_article(): """编辑文章""" form = ArticleForm() if form.validate_on_submit(): article = Article(title=form.title.data, content=form.content.data) article.tags = form.tags.data article.category = form.category.data try: db.session.add(article) db.session.commit() except: db.session.rollback() return render_template('dashboard/edit.html', form=form)
代码是不是很简洁了?^_^。。。
当然了写一个完整的WTForms扩展还是很麻烦的。这里只是刚刚入门。可以看官方扩展QuerySelectField的源码。。。
效果:
更多Python의 Flask에서 WTForms 양식 프레임워크 사용相关文章请关注PHP中文网!