Flask-AppBuilderでBaseViewを学習する
目的
環境構築は済んでいるものとする。
済んでいない方は以下を参考にしてください。
AppBuilder自体の参考記事がほとんどないので、公式ドキュメントを元に進めていきます。
BaseView
BaseView
公式ドキュメントの参考ページ
1. URLのみのルーティングでViewを表示する
from flask_appbuilder import AppBuilder, expose, BaseView
from app import appbuilder
class MyView(BaseView):
route_base = "/myview" # ①
@expose('/method1/<string:param1>') # ②
def method1(self, param1):
# do something with param1
# and return it
return param1
@expose('/method2/<string:param1>') # ③
def method2(self, param1):
# do something with param1
# and render it
param1 = 'Hello %s' % (param1)
return param1
appbuilder.add_view_no_menu(MyView()) # ④
1-1. route_base = "/myview"
ルーティングを定義しています。
http://localhost:5000/
以下に/myview
を打ち込みアクセス形にしています。
string:param1')
1-2. @expose('/method1/ルーティングの/myview
の後に/method1/[任意の文字列]
を打ち込むと、打ち込んだ任意の文字列がviewとして表示されます。
string:param1')
1-3. @expose('/method2/2とほぼ同じですが、/method2/[任意の文字列]
を打ち込むと、hello+任意の文字列がviewとして表示されます。
1-4. appbuilder.add_view_no_menu(MyView())
APIの構文です。
メニューを作成せずにviewを追加します。
1-5. アクセスしてみる
※johnは任意の文字列です
2. メニューの作成を伴うViewの表示(+@has_access)
パターン2として、先ほどのview.py
を変更します。
メニューを作成し、アクセスするとViewが表示されるようにします。
from flask_appbuilder import AppBuilder, BaseView, expose, has_access
from app import appbuilder
class MyView(BaseView):
default_view = 'method1'
@expose('/method1/') # ②
@has_access
def method1(self):
# do something with param1
# and return to previous page or index
return 'Hello'
@expose('/method2/<string:param1>') # ④
@has_access
def method2(self, param1):
# do something with param1
# and render template with param
param1 = 'Goodbye %s' % (param1)
return param1
appbuilder.add_view(MyView, "Method1", category='My View') # ①
appbuilder.add_link("Method2", href='/myview/method2/john', category='My View') # ③
2-1. appbuilder.add_view(MyView, "Method1", category='My View')
add_view
を使用すると、メニューに関連づけられたviewを追加出来ます。
メニュー名 -> MyView
MyView内にMethod1という名前で追加します。
2-2. @expose('/method1/')
MyViewからMethod1を選択するとhttp://localhost:5000/myview/method1/
にアクセスし、helloという文字列のviewが表示されます。
@has_access
でセキュリティで保護されたメソッドですよーとFlaskに伝えています。
2-3. appbuilder.add_link("Method2", href='/myview/method2/john', category='My View')
add_link
は①で作成されたMyViewという名前のメニューにリンクを追加出来ます。
リンク名 -> Method2
リンクURL -> /myview/method2/john
MyView内のMethod2を選択するとhttp://localhost:5000/myview/method2/john
にアクセスします。
string:param1')
2-4. @expose('/method2/引数に指定されたparam1は③で入力されるリンク名/myview/method2/john
のjohn
に当たります。
なので、③のリンク先にアクセスすると、param1がreturnとなっているので、Goodbye + johnが表示されます。
3. look and feelを伴うviewの作成
公式の説明文を引用します
Notice that these methods will render simple pages not integrated with F.A.B’s look and feel. It’s easy to render your method’s response integrated with the app’s look and feel, for this you have to create your own template. Under your project’s directory and app folder create a folder named ‘templates’. Inside it create a file name ‘method3.html’
3-1. templates, htmlの作成
create-app
でappを作成すると自動でtemplatesディレクトリが作成されているとは思いますが、ない場合は作成したappディレクトリの直下にtemplatesディレクトリを作成し、method3.html
という名前でhtmlファイルを作成します。
{% extends "appbuilder/base.html" %}
{% block content %}
<h1>{{param1}}</h1>
{% endblock %}
公式から解釈すると、「appbuilder/base.html」を拡張し、ブロックコンテンツをオーバーライドしています。
(appbuilderが元々用意しているものを使って、それをオーバーライドしているという認識で良いはずです)
3-2. MyViewクラスにメソッドを追加する
2.で作成したview.py
の中のMyViewクラスにメソッドを追加します。
新しいテンプレートのレンダリングはappを作成した段階であるはずですが、なければ追加してください。
(記述する場所はmethod2の下でかまいません。)
from flask import render_template
@expose('/method3/<string:param1>')
@has_access
def method3(self, param1):
# do something with param1
# and render template with param
param1 = 'Goodbye %s' % (param1)
self.update_redirect()
return self.render_template('method3.html',
param1 = param1)
appbuilder.add_link("Method3", href='/myview/method3/john', category='My View')
3-1.で作成したテンプレートをレンダリングします。
メニューにmethod3が追加され、選択するとhttp://localhost:5000/myview/method3/john
にアクセスし、Goodbye johnという文字列のviewが表示されます。
self.update_redirect()
は、説明を見た感じだけだと理解しきれませんが、セッションやクッキーを利用する際(フォームなど)に便利な感じです。
self.render_template
はバージョン1.3.0以降、すべてのビューテンプレートをレンダリングする必要があるようです。
4. フォーム ビュー
view.py
と同じ階層にform.py
を作成します。
view.py
を記述し、作成したform.py
をimportして呼び出します。
4-1. form.py
WTFormsを使用します。
ブラウザ用のviewから提出されるフォームのデータを使って作業する必要があるときは、コードは途端にとても読みづらくなります。
このプロセスをより管理しやすくするためにデザインされたライブラリが公開されています。そのなかのひとつが、WTFormsです。
from wtforms import Form, StringField
from wtforms.validators import DataRequired
from flask_appbuilder.fieldwidgets import BS3TextFieldWidget
from flask_appbuilder.forms import DynamicForm
class MyForm(DynamicForm):
field1 = StringField(('Field1'),
description=('Your field number one!'),
validators = [DataRequired()], widget=BS3TextFieldWidget())
field2 = StringField(('Field2'),
description=('Your field number two!'), widget=BS3TextFieldWidget())
class MyFormを作成するに当たってFAB DynamicFormから継承します。
field1, field2と、2つの入力欄を作成します。
4-2. view.py
view.py
は上記で作成したform.py
をimportして呼び出します。
from flask import flash
from flask_appbuilder import SimpleFormView
from flask_babel import lazy_gettext as _
from . import appbuilder, db
from .form import MyForm
class MyFormView(SimpleFormView):
form = MyForm
form_title = 'This is my first form view'
message = 'My form submitted'
def form_get(self, form):
form.field1.data = 'This was prefilled'
def form_post(self, form):
# post process form
flash(self.message, 'info')
appbuilder.add_view(MyFormView, "My form View", icon="fa-group", label=_('My form View'),
category="My Forms", category_icon="fa-cogs")
メニューにMyFormsが追加されていて、投稿フォーム欄が2つ出来ています。
form_get
でフォームにデータを事前入力出来ます。
事前にThis was prefilled
が入力された状態になります。
form_post
はユーザがフォームを送信した後にフォームを後処理出来ます。
何かしらの値を入力するとmessage変数に入れたMy form submitted
が出力されます。
まとめ
AppBuilderの最低限のViewの表示の仕方を学びました。
軽量フレームワークであるため、自由度が高い反面覚えることが多そうな印象です。
Discussion