1. SQLEDITABLE デモ¶
目次
1.1. インフォメーション¶
- リポジトリ : https://github.com/hiho-/SQLEDITABLE
- バグ報告 : https://github.com/hiho-/SQLEDITABLE/issues
- ドキュメント : SQLEDITABLE ドキュメント
- 動作チェック : Chrome35, Firefox30, InternetExplorer11(document-mode edge,10,9,8,7), Silk
- ライセンス : LGPLv3
1.2. SQLEDITABLE 基本的な使い方¶
最初に、SQLEDITABLEのプラグインファイルをリンクからダウンロードし、アプリケーションにセットします。
https://github.com/hiho-/SQLEDITABLE/releases
- web2py.plugin.sqleditable.w2p - プラグインファイル
- web2py.app.demo.w2p - デモアプリ
モデル(db.pyなど)もしくはコントローラ(default.pyなど)に、次の記述を追加します。
from plugin_sqleditable.editable import SQLEDITABLE SQLEDITABLE.init()
後は、SQLFORM と同様に記述するだけです。
1.2.1. デモ1¶
Demo010 - リンクをクリックしてください
モデル定義
db.define_table('employee_sheet', Field('employee_number','integer',length=5,label='Emp.no.'), Field('name','string',length=50,notnull=True), Field('date_employment','date',label='Enter',requires=IS_DATE()), Field('employee_section','string',label='Section', requires=IS_IN_SET({'s':'sales','p':'production','d':'development', 'c':'control'})), Field('employee_comment','string',label='Comment'), Field('date_resignation','date',label='Exit',readable=False, requires=IS_EMPTY_OR(IS_DATE())), Field('resigned','boolean', writable=False, default=False), Field('remuneration','decimal(12,2)', readable=False), Field('currency','string',readable=False, requires=IS_IN_SET(['USD','EUR','GBP','JPY'])))コントローラ
def demo010(): response.title = 'demo010' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.employee_sheet, showid=False, maxrow=5).process() return dict(editable=editable)現在のところ、対応しているフィールドタイプは、interger , double , float , decimal, string , boolean , date , datetime , time です。
また、IS_IN_SET バリデータが記述されていると、リストボックスが表示されます。 IS_IN_DB にも対応しました(デモ13 - IS_IN_DB)。
1.2.2. デモ2 - 縦向き¶
Demo011 - リンクをクリックしてください
1.2.3. デモ3 - バリデート¶
Demo012 - リンクをクリックしてください
1.2.4. デモ4 - 削除¶
Demo020 - リンクをクリックしてください
コントローラ
def demo020(): db.employee_sheet.date_resignation.readable = True db.employee_sheet.resigned.writable = True db.employee_sheet.remuneration.readable = True db.employee_sheet.currency.readable = True response.title = 'demo020' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.employee_sheet, maxrow=5, deletable=True).process() return dict(editable=editable)
SQLEDITABLE
の前にテーブル属性を変更しています。 また、deletable=True
によって削除チェックボックスを表示しています。
1.2.5. デモ5 - レコード指定¶
Demo030 - リンクをクリックしてください
コントローラ
def demo030(): def record(): rows = db(db.employee_sheet).select( orderby=~db.employee_sheet.employee_number, limitby=(0,3)) return [row.id for row in rows.sort(lambda row:row.employee_number)] response.title = 'demo030' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.employee_sheet, record=record,showid=False, maxrow=5).process() return dict(editable=editable)
record
によって、レコードidを指定しています。 通常はリストで指定しますが、callableのため、DAL構文を記述してもOKです。 3行分を登録したデータで、2行分を新規データ用に表示します。
1.2.6. デモ6 - as_dict¶
Demo040 - リンクをクリックしてください
コントローラ
def demo040(): response.title = 'demo040' response.view = 'plugin_sqleditable/sample_as_dict.html' editable = SQLEDITABLE(db.employee_sheet, showid=False, maxrow=5).process() return editable.as_dict()
as_dict()
によって、シートとボタン、スクリプトを辞書でビューに渡します。 サンプルビューでは、editable
,button
,script
の各値の処理をしています。{{=button}} はビュー上に何個設置しても動作します。(changed:2015-02)
<table class='col-md-12'> <tr><td> {{=button}} </td></tr> <tr><td> {{=editable}} </td></tr> <tr><td> {{=button}} </td></tr> </table> {{block head}} {{super}} {{=script}} {{end}}
1.2.7. デモ7 - 画面遷移¶
Demo050 - リンクをクリックしてください
コントローラ
def demo050(): response.title = 'demo050' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.employee_sheet, showid=False, maxrow=5, deletable=True).process(next=URL('static', 'success.html')) return dict(editable=editable)next_js=URL(‘static’, ‘success.html’)
next=URL('static', 'success.html')
によって、成功時別画面に遷移します。(changed:2014-07-02)
1.2.8. デモ8¶
モデル定義
db.define_table('scadule_sheet', Field('scadule_date','date',label='date'), Field('scadule_time','time',label='time'), Field('term','integer'), Field('term_unit','string', requires=IS_IN_SET({'min':'minute','hr':'hour','d':'day','wk':'week', 'mo':'month'})), Field('detail','string',length=30,requires=IS_NOT_EMPTY()))コントローラ
def demo060(): response.title = 'demo060' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.scadule_sheet, showid=False, maxrow=8, deletable=True).process() return dict(editable=editable) def demo061(): response.title = 'demo061' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.scadule_sheet, showid=False, maxrow=8, deletable=True, vertical=False).process() return dict(editable=editable)別のテーブルを表示しています。
1.2.9. デモ9 - タッチデバイス¶
コントローラ
def demo070(): response.title = 'demo070' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.scadule_sheet, showid=False, maxrow=8, deletable=True, touch_device=True).process() return dict(editable=editable) def demo071(): response.title = 'demo071' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.scadule_sheet, showid=False, maxrow=8, deletable=True, touch_device=False).process() return dict(editable=editable) def demo072(): response.title = 'demo072' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.scadule_sheet, showid=False, maxrow=8, deletable=True, touch_device='Auto').process() return dict(editable=editable) def demo073(): response.title = 'demo073' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.scadule_sheet, showid=False, maxrow=8, deletable=True).process() return dict(editable=editable)date , time , datetime フィールド入力で、タッチデバイス用に入力方法を変更します。
touch_device パラメータが Auto もしくは指定しない場合は、
request.user_agent()
をチェックし、タッチデバイスと判定したアクセスでは、 web2pyのウィジェットではなく、HTML5対応のブラウザウィジェットを使用します。
1.2.10. デモ10 - 仮想フィールド¶
Demo090 - リンクをクリックしてください
モデル定義
db.define_table('employee_sheet', Field('employee_number','integer',length=5,label='Emp.no.'), Field('name','string',length=50,notnull=True), Field('date_employment','date',label='Enter',requires=IS_DATE()), Field('employee_section','string',label='Section', requires=IS_IN_SET({'s':'sales','p':'production','d':'development', 'c':'control'})), Field('employee_comment','string',label='Comment'), Field('date_resignation','date',label='Exit',readable=False, requires=IS_EMPTY_OR(IS_DATE())), Field('resigned','boolean', writable=False, default=False), Field('remuneration','decimal(12,2)', readable=False), Field('currency','string',readable=False, requires=IS_IN_SET(['USD','EUR','GBP','JPY']))) class san(object): def san(self): return self.employee_sheet.name + '-san' db.employee_sheet.virtualfields.append(san()) db.employee_sheet.san2 = Field.Virtual(lambda row: row.employee_sheet.name + '-SAN')コントローラ
def demo090(): response.title = 'demo090' response.view = 'plugin_sqleditable/sample.html' header = ['employee_number','name','san','san2'] editable = SQLEDITABLE(db.employee_sheet, header=header, showid=False, maxrow=5, deletable=True).process() return dict(editable=editable)仮想フィールドを表示します。
header
パラメータで表示フィールドを指定します。仮想フィールドでラベルを表示する場合、
field
とlabel
を使用ください。def demo090(): response.title = 'demo090' response.view = 'plugin_sqleditable/sample.html' header = ['employee_number','name',{'field':'san2','label':'xxxx'}] editable = SQLEDITABLE(db.employee_sheet, header=header, showid=False, maxrow=5, deletable=True).process() return dict(editable=editable)辞書型で
field
に仮想フィールドを、label
にはラベルを指定します。なお、旧タイプの仮想フィールドでは動作しません(サンプルコードの san は旧タイプ仮想フィールド)。
1.2.11. デモ11 - アンカーリンク¶
Demo091 - リンクをクリックしてください
モデル定義
db.define_table('employee_sheet', Field('employee_number','integer',length=5,label='Emp.no.'), Field('name','string',length=50,notnull=True), Field('date_employment','date',label='Enter',requires=IS_DATE()), Field('employee_section','string',label='Section', requires=IS_IN_SET({'s':'sales','p':'production','d':'development', 'c':'control'})), Field('employee_comment','string',label='Comment'), Field('date_resignation','date',label='Exit',readable=False, requires=IS_EMPTY_OR(IS_DATE())), Field('resigned','boolean', writable=False, default=False), Field('remuneration','decimal(12,2)', readable=False), Field('currency','string',readable=False, requires=IS_IN_SET(['USD','EUR','GBP','JPY']))) db.employee_sheet.history = Field.Virtual(lambda row: A('History', _href=URL(f='demo092', args=row.employee_sheet.id))) db.define_table('history_in_house', Field('employee',db.employee_sheet), Field('date_history','date',label='Enter',requires=IS_DATE()), Field('employee_section','string',label='Section', requires=IS_IN_SET({'s':'sales','p':'production','d':'development', 'c':'control'})))コントローラ
def demo091(): response.title = 'demo091' response.view = 'plugin_sqleditable/sample.html' header = ['employee_number','name','history'] editable = SQLEDITABLE(db.employee_sheet, header=header, showid=False, maxrow=5, deletable=True).process() return dict(editable=editable) def demo092(): def record(): session.employee = request.args(0) rows = db(db.history_in_house.employee==request.args(0)).select( orderby=~db.history_in_house.date_history, limitby=(0,4)) return [row.id for row in rows.sort(lambda row:row.date_history)] def onvalidation(form): form.vars.employee = session.employee db.history_in_house.employee.readable = False response.title = 'demo092' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.history_in_house, record=record, showid=False, maxrow=5, deletable=True).process(onvalidation=onvalidation) return dict(editable=editable)アンカーリンクを仮想フィールドを使って表示します。
header
パラメータで表示フィールドを指定します。 リンク先のテーブルでは、関連するレコードのみを表示します。このため、 processメソッドでonvalidation
パラメータを指定しています。 onvalidation 関数内で、 employee フィールドの値としてURLパラメータ値を指定しています(record関数内で、一旦セッションに値を渡しています)。なお、仮想フィールドの記述を次のように変更すれば、ボタン部品で配置することも可能です。
db.employee_sheet.history = Field.Virtual(lambda row: BUTTON('Hisotry', _onClick="location.href='%s'" % URL(f='demo092', args=row.employee_sheet.id)))onvalidation パラメータを使用せず、 次のように demo092 コントローラを記述することも可能です。フィールドのデフォルト値を設定しています(9行目)。
def demo092(): def record(): session.employee = request.args(0) rows = db(db.history_in_house.employee==request.args(0)).select( orderby=~db.history_in_house.date_history, limitby=(0,4)) return [row.id for row in rows.sort(lambda row:row.date_history)] db.history_in_house.employee.readable = False db.history_in_house.employee.default = session.employee response.title = 'demo092' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.history_in_house, record=record, showid=False, maxrow=5, deletable=True).process() return dict(editable=editable)
1.2.12. デモ12 - onvalidation¶
Demo100 - リンクをクリックしてください
モデル定義
db.define_table('employee_sheet', Field('employee_number','integer',length=5,label='Emp.no.'), Field('name','string',length=50,notnull=True), Field('date_employment','date',label='Enter',requires=IS_DATE()), Field('employee_section','string',label='Section', requires=IS_IN_SET({'s':'sales','p':'production','d':'development', 'c':'control'})), Field('employee_comment','string',label='Comment'), Field('date_resignation','date',label='Exit',readable=False, requires=IS_EMPTY_OR(IS_DATE())), Field('resigned','boolean', writable=False, default=False), Field('remuneration','decimal(12,2)', readable=False), Field('currency','string',readable=False, requires=IS_IN_SET(['USD','EUR','GBP','JPY'])))コントローラ
def demo100(): def onvalidation(form): if len(form.vars.name) < 5: form.errors.name = 'Enter 5 characters or more' else: form.vars.name = form.vars.name.title() response.title = 'demo100' response.view = 'plugin_sqleditable/sample.html' header = ['employee_number','name'] editable = SQLEDITABLE(db.employee_sheet, header=header, showid=False, maxrow=5, deletable=True, update_display_record=True).process(onvalidation=onvalidation) return dict(editable=editable)onvalidation パラメータのデモです。processメソッドで
onvalidation
パラメータを指定しています。 web2py の Form と同様に、form.vars.xxx や form.errors.xxx 変数を使用できます。 onvalidation関数内でフィールド値を変更した場合、通常はテーブルの表示は変更されません。このため、SQLEDITABLEのパラメータのupdate_display_record
を True にすると、 変更された値にテーブルの表示が更新されます。
1.2.13. デモ13 - IS_IN_DB¶
Demo093 - リンクをクリックしてください
モデル定義
db.define_table('employee_sheet', Field('employee_number','integer',length=5,label='Emp.no.'), Field('name','string',length=50,notnull=True), Field('date_employment','date',label='Enter',requires=IS_DATE()), Field('employee_section','string',label='Section', requires=IS_IN_SET({'s':'sales','p':'production','d':'development', 'c':'control'})), Field('employee_comment','string',label='Comment'), Field('date_resignation','date',label='Exit',readable=False, requires=IS_EMPTY_OR(IS_DATE())), Field('resigned','boolean', writable=False, default=False), Field('remuneration','decimal(12,2)', readable=False), Field('currency','string',readable=False, requires=IS_IN_SET(['USD','EUR','GBP','JPY'])), format='%(name)s') db.define_table('history_in_house', Field('employee',db.employee_sheet), Field('date_history','date',label='Enter',requires=IS_DATE()), Field('employee_section','string',label='Section', requires=IS_IN_SET({'s':'sales','p':'production','d':'development', 'c':'control'})))コントローラ
def demo093(): response.title = 'demo093' response.view = 'plugin_sqleditable/sample.html' editable = SQLEDITABLE(db.history_in_house, showid=False, maxrow=5, deletable=True).process() return dict(editable=editable)IS_IN_DB バリデータをサポートするようになりました。 セレクトボックスから、他のテーブルのデータを表示します。フィールドに IS_IN_DB バリデータをセットするか、 web2pyによる暗黙設定によってリンク先データをセレクトボックスに表示可能です(暗黙設定では、リンク先のテーブルに format 設定が必要です)。
1.2.14. デモ14 - 自己参照型フィールド¶
モデル定義
db.define_table('node', Field('parent_id','reference node'), Field('name'), Field('node_comment'))コントローラ
def demo110(): def record(): session.parent_id = request.args(0) if request.args(0) else None rows = db(db.node.parent_id==request.args(0)).select() rec = [row.id for row in rows] return rec def parent(): parent = [] if session.parent_id: row = db.node(session.parent_id) if row: parent.insert(0, LI(row.name, _class='active')) while row: if row.parent_id: row = db.node(row.parent_id) if row: parent.insert(0, LI(A(row.name, _href=URL(f='demo110', args=row.id)))) else: break parent.insert(0, LI(A('Top', _href=URL(f='demo110')))) return OL(parent, _class='breadcrumb') db.node.children = Field.Virtual(lambda row: A(I(_class='glyphicon glyphicon-arrow-right'), ' Children', _class='btn btn-default btn-sm', _href=URL(f='demo110', args=row.node.id))) response.title = 'demo110' db.node.parent_id.default = session.parent_id header = ['name', 'node_comment', 'children'] editable = SQLEDITABLE(db.node, record=record, maxrow=10, showid=False, deletable=True, header=header).process() return dict(editable=editable, parent=parent())ビュー
<table class='col-md-12'> <tr><td> {{=parent}} </td></tr> <tr><td> {{=editable}} </td></tr> </table>自己参照型フィールドを使ったアプリの例です。
parent
辞書変数を追加しています。
as_dict()
メソッドを利用する場合は、直接editable
に変数を追加するのではなく、as_dict()のパラメータとして渡す必要があります。コントローラ
def demo111(): def record(): session.parent_id = request.args(0) if request.args(0) else None rows = db(db.node.parent_id==request.args(0)).select() rec = [row.id for row in rows] return rec def parent(): parent = [] if session.parent_id: row = db.node(session.parent_id) if row: parent.insert(0, LI(row.name, _class='active')) while row: if row.parent_id: row = db.node(row.parent_id) if row: parent.insert(0, LI(A(row.name, _href=URL(f='demo111', args=row.id)))) else: break parent.insert(0, LI(A('Top', _href=URL(f='demo111')))) return OL(parent, _class='breadcrumb') db.node.children = Field.Virtual(lambda row: A(I(_class='glyphicon glyphicon-arrow-right'), ' Children', _class='btn btn-default btn-sm', _href=URL(f='demo111', args=row.node.id))) response.title = 'demo111' db.node.parent_id.default = session.parent_id header = ['name', 'node_comment', 'children'] editable = SQLEDITABLE(db.node, record=record, maxrow=10, showid=False, deletable=True, header=header).process() return editable.as_dict(parent=parent())ビュー
<table class='col-md-12'> <tr><td> {{=parent}} </td></tr> <tr><td> {{=button}} {{=editable}} {{=button}} </td></tr> </table> {{block head}} {{super}} {{=script}} {{end}}
1.2.15. デモ15 - Field.Method¶
Demo120 - リンクをクリックしてください
コントローラ
def demo120(): def record(): session.parent_id = request.args(0) if request.args(0) else None rows = db(db.node.parent_id==request.args(0)).select() rec = [row.id for row in rows] if request.args(0): rec.insert(0, request.args(0)) return rec def parent(): parent = [] if session.parent_id: row = db.node(session.parent_id) if row: parent.insert(0, LI(row.name, _class='active')) while row: if row.parent_id: row = db.node(row.parent_id) if row: parent.insert(0, LI(A(row.name, _href=URL(f='demo120', args=row.id)))) else: break parent.insert(0, LI(A('Top', _href=URL(f='demo120')))) return OL(parent, _class='breadcrumb') def onvalidation(form): if form.delete and form.vars.id == session.parent_id: form.errors.delete = 'This record is a parent and you can not be removed.' def argument(): return int(session.parent_id) if session.parent_id else None db.node.children = Field.Method(lambda row, parent_id: A(I(_class='glyphicon glyphicon-arrow-right'), ' Children', _class='btn btn-default btn-sm', _href=URL(f='demo120', args=row.node.id)) \ if row.node.id!=parent_id else SPAN(I(_class='glyphicon glyphicon-home'), ' Parent')) response.title = 'demo120' db.node.parent_id.default = session.parent_id header = ['name', 'node_comment', {'field':'children','argument':argument}] editable = SQLEDITABLE(db.node, record=record, maxrow=10, showid=False, deletable=True, header=header).process(onvalidation=onvalidation) return dict(editable=editable, parent=parent())Field.Method を使用したデモです。Field.Method フィールドの情報は
header
パラメータに、{'field':'children','argument':argument}のように指定します。辞書型の
field
キーの値にフィールド名を、argument
キーの値にパラメータを指定します。 Field.Method のパラメータは遅延評価のために、呼び出し可能オブジェクト(callable)である必要があります。
1.2.16. デモ16 - ページネーション¶
Demo140 - リンクをクリックしてください
コントローラ
def demo140(): # page limit = 5 dbset = db(db.employee_sheet) rows_count = dbset.count() total_page = rows_count // limit + 1 if rows_count % limit < limit else rows_count // limit page = int(request.vars.page) if request.vars.page and int(request.vars.page) <= total_page else 0 vars = request.get_vars vars['page'] = page-1 previous = LI(A('prev', _href=URL(vars=vars, user_signature=True))) if page else '' vars['page'] = page+1 if request.post_vars.keywords: vars['keywords'] = request.post_vars.keywords next = LI(A('next', _href=URL(vars=vars, user_signature=True))) if page*limit+limit <= rows_count else '' page_no = LI('{0}/{1}'.format(page+1, total_page), _style='margin-right:10px;') pagination = TAG.nav(UL(CAT(page_no, previous, next)), _class='pager') response.title = 'demo140' rows = dbset.select(orderby=db.employee_sheet.employee_number, limitby=(page*limit, page*limit+limit)) editable = SQLEDITABLE(db.employee_sheet, rows, showid=False, maxrow=limit, deletable=True).process() return dict(editable=editable, pagination=pagination)ビュー
<table class='col-md-12'> <tr><td> {{=editable}} </td></tr> <tr><td> {{=pagination}} </td></tr> </table>大きな表の更新に時間が掛かったり、エラーが発生する場合があります。
この場合は、表を分割表示するテクニックが必要になります。デモ16では、表をページ分割しています。