python Bottleの基本9 Form

###このテーマは、入力フォームをサクッと作るです。特に日本語入力があるフォームは、文字化けしたりフォームが崩れたり、すべったり転んだりします。そこでテンプレートを作っておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/0c73934a-ff7e-03b5-1ef0-77f9cebf8001.png)

```ex9.py
from bottle import *
import json,os
#HTML デコレーション(Bootstrap4)
def Html(title):
    html='''
        <!DOCTYPE html>
            <html lang="ja">
            <head>
                <meta charset="utf-8" />
                <title>%s</title>
                <link rel="stylesheet" type="text/css" href="/static/content/bootstrap.min.css" />
	            <link href="static/content/jumbotron.css" rel="stylesheet" />
                <link rel="stylesheet" type="text/css" href="/static/content/site.css" />
                <script src="/static/scripts/modernizr-2.6.2.js"></script>
                <script src="/static/scripts/jquery-1.10.2.min.js"></script>
                <script src="/static/scripts/bootstrap.min.js"></script>
                <script src="/static/scripts/respond.min.js"></script>
	            <script src="/static/scripts/mindmup-editabletable.js"></script>
            </head>
            <body>
            %s          
            </body>
            </html>'''
    def f0(f):
        def f1(*a,**b):          
            return html%(title,f(*a,**b))
        return f1
    return f0
def Body():
    def f0(f):
        def f1(*a,**b):
            return '<div class="container body-content">%s</div>'%f(*a,**b)
        return f1
    return f0
def Navi(menu):
    nav='''<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
            <a class="navbar-brand" href="/">%s</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarsExampleDefault">
            <ul class="navbar-nav mr-auto">
                %s
            </ul>
            <form class="form-inline my-2 my-lg-0">
                <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
            </form>
            </div>
     </nav>%s'''
    def f0(f):
        def f1(*a,**b):
            nm=''.join(['<li class="nav-item"><a class="nav-link" href="/%s">%s</a></li>'%(x,x) for x in menu[1:]])
            return nav%(menu[0],nm,f(*a,**b))
        return f1
    return f0
def routes(menu):
    def f0(f):
        route('/','GET',f)
        [route("/%s"%x,'GET',f) for x in menu]
        def f1(*a,**b):
            return f(*a,**b)
        return f1
    return f0
#JOMBOTRON デコレーション
def Jumbotron(title,paragraph):
    jumbo='''<div class="jumbotron">
        <div class="container">
          <h1 class="display-3">%s</h1>
          <p>%s</p>
        </div>
      </div>%s'''
    def f0(f):
        def f1(*a,**b):
            return jumbo%(title,paragraph,f(*a,**b))
        return f1
    return f0

def form(nm):   
    x0='''<div class="container" style="margin-top:2em;">
    <form class="form" role="form" action="/form" method="post">
        %s
        <button type="submit" class="btn btn-primary ">登録</button>
    </form>
</div>'''
    x1='<div class="form-group row">%s</div>'
    x2='''<label for="{0}" class="col-sm-4 control-label">{0}</label>
    <div class="col-sm-8">
        <input name="{0}" type="text" id="{0}" placeholder="{0}" class="form-control" autofocus>
    </div>'''
    ax=''.join([''.join([x1%x2.format(a) for a in x.split(' ')])for x in nm])
    return x0%ax
menu='Home,Form,Menu2,Menu3,Disp'.split(',')
@routes(menu)
@Html('Hello')
@Navi(menu)
@Jumbotron('Formテンプレート','これさえあればサクッと作ることができます')
@Body()
def Home():
    p=request.urlparts[2]
    if p=='/Form':
        return form("名前,電話番号,メール,郵便番号,住所".split(','))
    return "<h1>%s</h1><h1>Hello World</h1>"%(p)
def vTable(d):
        b="\n".join(["<tr><th>%s</th><td>%s</td></tr>"%(x,d[x])for x in d])
        h=["<table style='margin-top:3em;' class='table table-sm table-bordered table-striped table-responsive-sm table-hover'>",
           b,"</table>"]
        return "\n".join(h)+"<button class='btn btn-primary' onclick='history.back()'>戻る</button>"

@route('/form',method="POST")
@Html('Hello')
@Jumbotron('Form表示テンプレート','これさえあればサクッと作ることができます')
@Navi(menu)
@Body()
def form_post():
    tbl={x: request.params.decode()[x] for x in request.params.decode()}
    htm=vTable(tbl)
    return htm
#メニューの設定
#faviconの読み込み    
@route('/favicon.ico')
def favcon():
    return static_file('favicon.ico', root='./static')
#staic ファイルの読み込み
@route('/static/<filepath:path>')
def server_static(filepath):
    return static_file(filepath, root='./static')
#web server のhost portの設定
HOST,PORT='localhost',8080
if __name__ =='__main__':
    run(host=HOST,port=PORT)
```
# スニペット解説

```
return form("名前,電話番号,メール,郵便番号,住所".split(','))
```
formのHtmlを生成しています。カンマ区切りの項目を変えれば自由にカスタマイズできます。

```
def form_post():
    tbl={x: request.params.decode()[x] for x in request.params.decode()}
    htm=vTable(tbl)
    return htm
```
POSTされたデータをUTF-8にでコードしてdictを作っています。
vTableは、垂直方向に見出しするテーブルのhtmlを生成しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/274715/e59dcf93-a10e-0e69-decd-3bf008944497.png)