ホームページ バックエンド開発 Python チュートリアル Python の Flask で WTForms フォーム フレームワークを使用する

Python の Flask で WTForms フォーム フレームワークを使用する

Mar 03, 2017 pm 02:17 PM

ダウンロードしてインストールします

WTForms をインストールする最も簡単な方法は、easy_install と pip を使用することです:

easy_install WTForms
# or
pip install WTForms
ログイン後にコピー

WTForms を PyPI から手動でダウンロードし、python setup.py install を実行できます。あらゆるリスクを許容する場合は、Git から最新バージョンを実行するか、最新の変更セットのパッケージ バージョンを入手するか、プロジェクトのホームページにアクセスしてコード リポジトリを複製することができます。

主な概念

Forms クラス。 WTForms のコア コンテナです。フォーム (フォーム) は、フォームの辞書フォームまたは属性フォームを通じてアクセスできるフィールドのコレクションを表します。各フィールド (フィールド) は最も重要な作業を行います。たとえば、InputRequired と StringField は、フィールドに含まれるデータに加えて、ラベル、説明、フィールドなどの便利なプロパティも多数含みます。検証エラーのリスト
各フィールド (フィールド) はウィジェット (パーツ) インスタンスを所有します。ウィジェットの役割は、フィールド (フィールド) の HTML 表現をレンダリングすることですが、各フィールドにはウィジェット インスタンスがあります。一部のフィールドはシンプルで便利です。たとえば、TextAreaField は、デフォルトのウィジェットが TextArea である単なる
StringField です。検証ルールを指定するために、フィールドには

Start

を含めます。早速本題に入り、最初のフォームを定義します: :

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()])
ログイン後にコピー

フォームを作成するとき、フィールドを定義する方法は、多くの ORM が列を定義する方法と似ています。つまり、クラス変数、つまりフィールドのインスタンスを定義します。

Forms は通常の Python クラスであり、必要なものに簡単に拡張できるためです::

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)])
ログイン後にコピー

サブクラス化することで、AdminProfileForm クラスは、すでに定義されている ProfileForm クラスのすべてのフィールドを取得できます。簡単に異なるフォーム間で共通のフィールドのサブセットを共有するには、ProfileForm に管理者専用フィールドを追加します。

フォームの使用

フォームの使用は、次の Django をインスタンス化するのと同じくらい簡単です。 -style View 関数。以前に定義した RegistrationForm クラスを使用します::


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)
ログイン後にコピー

まず、フォームをインスタンス化し、request.POST で利用可能なデータを提供します。次に、リクエストが POST メソッドを使用しているかどうかを確認します。そうであれば、フォームを検証し、ユーザーがこれらのルールに従っていることを確認します。成功した場合は、新しいユーザー モデルを作成し、検証されたフォームからデータを割り当て、最後に

既存のオブジェクトを編集します

前の登録例では、入力を受け取り、新しいエントリを検証する方法を示しましたが、既存のオブジェクトを編集したい場合はどうすればよいでしょうか?非常に単純です::

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)
ログイン後にコピー

ここでは、request.POST とユーザー オブジェクトの両方をフォームに提供することでフォームをインスタンス化します。これにより、フォームは、フォームに表示されないユーザー オブジェクトからデータを取得します。送信されたデータ

また、フォームの Populate_obj メソッドを使用して、検証されたフォームの内容をユーザー オブジェクトに再設定します。このメソッドは、フィールド名がデータを提供するオブジェクトの名前と一致する場合に便利です。手動で値を割り当てたいと思うかもしれませんが、この単純な例では、それが最適です。

コンソールで探索してください

WTForms フォームは非常に単純なコンテナ オブジェクトです。フォームで何が機能するかを見つける最も簡単な方法は、コンソールでフォームを試してみることです:

>>> 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&#39;test&#39;
>>> form.validate()
False
>>> form.errors
{&#39;username&#39;: [u&#39;Field must be at least 5 characters long.&#39;]}
ログイン後にコピー

フォームをインスタンス化すると、フォームにはフィールドのインスタンスがすべて含まれていることがわかります。フィールドへのアクセスは、辞書形式または属性形式で行うことができます。

フォームを検証すると、少なくとも 1 つの検証ルールが満たされていないことを意味する独自のプロパティが返されます。 form.errors はすべてのエラーの概要を示します。

>>> form2 = UsernameForm(username=u&#39;Robert&#39;)
>>> form2.data
{&#39;username&#39;: u&#39;Robert&#39;}
>>> form2.validate()
True
ログイン後にコピー

今回は、UserForm をインスタンス化するときに新しい値を username に渡します。これでフォームを確認するのに十分です。

フォームの取得方法データ

例外 最初の 2 つのパラメーター (formdata と obj) を使用してデータを提供することに加えて、フォームに入力するためにキーワード パラメーターを渡すこともできます。formdata、obj、prefix などの一部のパラメーター名は予約されていることに注意してください。

formdata は次のようになります。例:

def change_username(request):
 user = request.current_user
 form = ChangeUsernameForm(request.POST, user, username=&#39;silly&#39;)
 if request.method == &#39;POST&#39; and form.validate():
  user.username = form.username.data
  user.save()
  return redirect(&#39;change_username&#39;)
 return render_response(&#39;change_username.html&#39;, form=form)
ログイン後にコピー

実際には 3 つの方法をすべて一緒に使用することはほとんどありませんが、WTForms がユーザー名フィールドを検索する方法の例を次に示します。フォームが送信された場合 (リクエスト .POST が空でない場合)、実際には、このフィールドにフォーム入力がなくても、何らかのフォーム入力があればフォーム入力が処理されます。

フォーム入力がない場合は、次の順序で試してください:

ユーザーに username という名前の属性があるかどうかを確認します。


    username という名前のキーワード引数が指定されているかどうかを確認します。
  • 最後に、他のすべてが失敗した場合は、ドメインのデフォルト値を使用してください。
  • validator

    WTForms中的验证器(Validators)为域(field)提供一套验证器, 当包含域的表单进行验证时运行. 你提供验证器可通过域构造函数的第二个参数validators:

    class ChangeEmailForm(Form):
     email = StringField(&#39;Email&#39;, [validators.Length(min=6, max=120), validators.Email()])
    ログイン後にコピー

    你可以为一个域提供任意数量的验证器. 通常, 你会想要提供一个定制的错误消息:

    class ChangeEmailForm(Form):
     email = StringField(&#39;Email&#39;, [
      validators.Length(min=6, message=_(u&#39;Little short for an email address?&#39;)),
      validators.Email(message=_(u&#39;That\&#39;s not a valid email address.&#39;))
     ])
    ログイン後にコピー

    这通常更好地提供你自己的消息, 作为必要的默认消息是通用的. 这也是提供本地化错误消息的方法.

    对于内置的验证器的列表, 查阅 Validators.

    渲染域
    渲染域和强制它为字符串一样简单:

    >>> from wtforms import Form, StringField
    >>> class SimpleForm(Form):
    ... content = StringField(&#39;content&#39;)
    ...
    >>> form = SimpleForm(content=&#39;foobar&#39;)
    >>> str(form.content)
    &#39;<input id="content" name="content" type="text" value="foobar" />&#39;
    >>> unicode(form.content)
    u&#39;<input id="content" name="content" type="text" value="foobar" />&#39;
    ログイン後にコピー

    然而, 渲染域的真正力量来自于它的 __call__() 方法. 调用(calling)域, 你可以提供关键词参数, 它们会在输出中作为HTML属性注入.

    >>> form.content(style="width: 200px;", class_="bar")
    u&#39;<input class="bar" id="content" name="content" style="width: 200px;" type="text" value="foobar" />&#39;
    ログイン後にコピー

    现在, 让我们应用这个力量在 Jinja 模板中渲染表单. 首先, 我们的表单:

    class LoginForm(Form):
     username = StringField(&#39;Username&#39;)
     password = PasswordField(&#39;Password&#39;)
    
    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(&#39;Must be 42&#39;)
    
    class FourtyTwoForm(Form):
     num = IntegerField(&#39;Number&#39;, [is_42])
    ログイン後にコピー

    或者通过提供一个在表单内的特定域(in-form field-specific)的验证器:

    class FourtyTwoForm(Form):
     num = IntegerField(&#39;Number&#39;)
    
     def validate_num(form, field):
      if field.data != 42:
       raise ValidationError(u&#39;Must be 42&#39;)
    ログイン後にコピー

    编写WTForm扩展示例

    class TagListField(Field):
     widget = TextInput()
    
     def _value(self):
      if self.data:
       return u&#39;, &#39;.join(self.data)
      else:
       return u&#39;&#39;
    
     def process_formdata(self, valuelist):
      if valuelist:
       self.data = [x.strip() for x in valuelist[0].split(&#39;,&#39;)]
      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&#39;&#39;
       for obj in self.data:
        r += self.obj_to_str(obj)
       return u&#39;&#39;
      else:
       return u&#39;&#39;
    
     def process_formdata(self, valuelist):
      print &#39;process_formdata..&#39;
      print valuelist
      if valuelist:
       tags = self._remove_duplicates([x.strip() for x in valuelist[0].split(&#39;,&#39;)])
       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&#39;&#39;
    
    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&#39;&#39;
       for obj in self.data:
        r += self.obj_to_str(obj)
       return u&#39;&#39;
      else:
       return u&#39;&#39;
     
     def process_formdata(self, valuelist):
      print &#39;process_formdata..&#39;
      print valuelist
      if valuelist:
       tags = self._remove_duplicates([x.strip() for x in valuelist[0].split(&#39;,&#39;)])
       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&#39;&#39;
    ログイン後にコピー

    主要就是在process_formdata这一步处理表单的数据,将字符串转换为需要的数据。最终就可以在forms.py中这样定义表单了:

    ...
    class ArticleForm(Form):
     """编辑文章表单"""
    
     title = StringField(u&#39;标题&#39;, validators=[Required()])
     category = QuerySelectField(u&#39;分类&#39;, query_factory=get_category_factory([&#39;id&#39;, &#39;name&#39;]), get_label=&#39;name&#39;)
     tags = TagListField(u&#39;标签&#39;, validators=[Required()])
     content = PageDownField(u&#39;正文&#39;, validators=[Required()])
     submit = SubmitField(u&#39;发布&#39;)
    ...
    
    ...
    class ArticleForm(Form):
     """编辑文章表单"""
     
     title = StringField(u&#39;标题&#39;, validators=[Required()])
     category = QuerySelectField(u&#39;分类&#39;, query_factory=get_category_factory([&#39;id&#39;, &#39;name&#39;]), get_label=&#39;name&#39;)
     tags = TagListField(u&#39;标签&#39;, validators=[Required()])
     content = PageDownField(u&#39;正文&#39;, validators=[Required()])
     submit = SubmitField(u&#39;发布&#39;)
    ...
    在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(&#39;dashboard/edit.html&#39;, 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(&#39;dashboard/edit.html&#39;, form=form)
    ログイン後にコピー

    代码是不是很简洁了?^_^。。。

    当然了写一个完整的WTForms扩展还是很麻烦的。这里只是刚刚入门。可以看官方扩展QuerySelectField的源码。。。
    效果:

    Python の Flask で WTForms フォーム フレームワークを使用する

    更多Python の Flask で WTForms フォーム フレームワークを使用する相关文章请关注PHP中文网!

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? LinuxターミナルでPythonバージョンを表示するときに発生する権限の問題を解決する方法は? Apr 01, 2025 pm 05:09 PM

LinuxターミナルでPythonバージョンを表示する際の許可の問題の解決策PythonターミナルでPythonバージョンを表示しようとするとき、Pythonを入力してください...

プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は? Apr 02, 2025 am 07:18 AM

10時間以内にコンピューター初心者プログラミングの基本を教える方法は?コンピューター初心者にプログラミングの知識を教えるのに10時間しかない場合、何を教えることを選びますか...

あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? あるデータフレームの列全体を、Python内の異なる構造を持つ別のデータフレームに効率的にコピーする方法は? Apr 01, 2025 pm 11:15 PM

PythonのPandasライブラリを使用する場合、異なる構造を持つ2つのデータフレーム間で列全体をコピーする方法は一般的な問題です。 2つのデータがあるとします...

中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? 中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか? Apr 02, 2025 am 07:15 AM

fiddlereveryversings for the-middleの測定値を使用するときに検出されないようにする方法

正規表現とは何ですか? 正規表現とは何ですか? Mar 20, 2025 pm 06:25 PM

正規表現は、プログラミングにおけるパターンマッチングとテキスト操作のための強力なツールであり、さまざまなアプリケーションにわたるテキスト処理の効率を高めます。

uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? uvicornは、serving_forever()なしでhttpリクエストをどのように継続的に聞いていますか? Apr 01, 2025 pm 10:51 PM

UvicornはどのようにしてHTTPリクエストを継続的に聞きますか? Uvicornは、ASGIに基づく軽量のWebサーバーです。そのコア機能の1つは、HTTPリクエストを聞いて続行することです...

文字列を介してオブジェクトを動的に作成し、Pythonでメソッドを呼び出す方法は? 文字列を介してオブジェクトを動的に作成し、Pythonでメソッドを呼び出す方法は? Apr 01, 2025 pm 11:18 PM

Pythonでは、文字列を介してオブジェクトを動的に作成し、そのメソッドを呼び出す方法は?これは一般的なプログラミング要件です。特に構成または実行する必要がある場合は...

人気のあるPythonライブラリとその用途は何ですか? 人気のあるPythonライブラリとその用途は何ですか? Mar 21, 2025 pm 06:46 PM

この記事では、numpy、pandas、matplotlib、scikit-learn、tensorflow、django、flask、and requestsなどの人気のあるPythonライブラリについて説明し、科学的コンピューティング、データ分析、視覚化、機械学習、Web開発、Hの使用について説明します。

See all articles