LoginSignup
1
0

More than 5 years have passed since last update.

POST.body を Json形式で渡す方法[python-by.bottle]

Last updated at Posted at 2019-03-27

form内のinputタグ全てをjsonにして...

POSTは、formデータをサーバへ送信する際に活用するタグで、その中のinputタグに含まれるデータをサーバ側で受け取るのは、特に面倒だったりもする...
例えば、<input type="text" name="id" id="id">とか、<input type="text" name="id" id="name">とか...紛らわしい上に扱いづらい、そしてサーバ側の言語には予約されていたりするので、さらに変数名を安易に考えられたものについては面倒...
そこで単純に、jsonデータにして受け渡し、サーバ側でも受け取りをjson形式にする事で、加工や挿入、代入などが可能になり、処理もフロント側だけでほぼ完結したりもできる。

準備するもの

サーバサイド

  • Python3.6<=x
  • Tinydb
  • bottle

フロントエンド

  • javascript
  • html
  • Chrome

実際のコード


実際と言いつつも、実行はしていないwけど、多分、動く...
※コメント頂ければ、修正します。

これらは、ただ抜粋しただけだから動かない可能性もあるが、
ポイントを押さえておけば問題ないはず...
まずは、js側から...その次に、サーバ側の処理について...説明したいと思う。

app.py
import bottle
from bottle import request
from tinydb import TinyDB as tydb


@route("/")
def index():
    index = """
       <!DOCTYPE html>
        <html lang="ja">
          <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Post 2 Json</title>
          </head>
          <body>
               <form action="/db" method="POST" id="form_cnts" name="form_cnts" enctype="multipart/form-data">

            USER: <input type="text" name="user" id="user">
            <br>
            PASSWORD: <input type="text" name="paswd" id="paswd">
            <input type="hidden" name="secret_key" id="secret_key" value="b42c66d06dc047e191aab859429a0105">
            </form>
          <script>
             /*---------------------------------------------------- $ ---------------------------------------------------------------*/
             /** ID と Classを変換する関数
              * $('#id')
              * @param  {String} - let id_name = $('#id')
              * @return {Object} - id-tag
              */
             if (String.prototype.$ == undefined){
               $ = (x) => {
                 const idn = /^#/g
                 if (typeof x == "string") {
                   if(x.match(idn)) return document.getElementById(x.replace(idn, ""))
                 }
                 return x
               }
             }

          let PostDB = (e) => {
             e.preventDefault()
             let JD           = {}

             let FORMCNTS     = $("#form_cnts")
             let INPUT_DATA   = document.getElementsByTagName('input')
             for(let d of Object.values(INPUT_DATA)){JD[d.name]=d.value}
             let JSON_DATA    = '['+JSON.stringify(JD).toString()+']'
             let CUSTOM_HEADER = "CUSTOM-HEADER-NAME"
             let customHeaders = new Headers({'Content-Type': 'application/json','X- 
             Custom-Header': CUSTOM_HEADER })
             let customInit = { method: 'POST',
                             headers: customHeaders,
                             Accept: 'application/json',
                             mode: 'cors',
                             cache: 'default',
                             credentials: 'same-origin',
                             body: JSON.stringify(JSON_DATA)}
            let url = FORMCNTS.action

            let customRequest = new Request(url, customInit)
            fetch(customRequest)
            .then((response) => {
              return response.json()
            })
            .then((resp) => {
              if(resp.status == "OK") {
                for(let d of Object.values(INPUT_DATA)){d.value=""}
                let fade_div          = $("#fade_div")
                fade_div.innerText    = resp.status
                fadeIn(fade_div,1500,function(){
                 fadeOut(fade_div,1500,function(){
                  })
              })
              }
             })
             .catch(function(error) { console.log(error) })
          }
          </script>
          </body>
        </html>
    """
    return index

@post('/db')
def do_db():
    TYDB      = f'{TMP_PATH}/{DATABASE["NAME"]}.json'
    _status   = "NG"
    json_data = {"status": _status}
    if request.json != "":
        with tydb(TYDB) as db:
            json_data  = json.loads(request.json)
            db.insert(json_data[0])
        _status = "OK"
    try:
        reurl = json_data
        request_data = {
            "headers":request.headers['Content-Type'],
            "json": json_data,
            "MEMFILE_MAX":request.MEMFILE_MAX,
            "remote_route":request.remote_route,
            "is_xhr":request.is_xhr,
            "remote_addr":request.remote_addr,
            "url":request.url,
            "method":request.method,
            "status":_status,
            "User_Agent":request.get_header('User-Agent')}

        response.content_type = 'application/json'
        r = HTTPResponse(status=302)
        r.set_header('Location', reurl)

        return dumps(request_data, ensure_ascii=False, indent=2)
    except:
        abort(500)

if __name__ == "__main__":
    bottle.run(host='0.0.0.0', port=8080)

と、実行されれば、form内のデータがデータベースに登録されるだろう...
まずは、jsの説明から...
ここが重要で、TagName=inputを全て、INPUT_DATAへ格納する。
その後、for文で全て抜き出す。その際、name(key)とvalueで紐付けしながら格納する。
もしかすると、もっといい方法があるだろう...

...
let INPUT_DATA   = document.getElementsByTagName('input')
for(let d of Object.values(INPUT_DATA)){JD[d.name]=d.value}
...

その後、一度連想配列にする。
何故か?は、サーバ側の処理を確認するといいだろう。
日本語などがあると通常通り引き渡せない事があったので、救済処置として、このような形にしてみた。

let JSON_DATA    = '['+JSON.stringify(JD).toString()+']'

あとは、非同期処理のfetchを使ってPOSTすればいい。
その時重要になるのが、Content-Typeだ。これをjsonにしておかないと、受け渡しの際に、サーバ側で処理が複雑になってしまう。

... customHeaders = new Headers({'Content-Type': 'application/json',...

最後となるが、サーバ側の処理をみてみよう。

...json.loads(request.json)
...db.insert(json_data[0])

と、上記のようにjson形式で呼び出した上で、データベースへ格納する際には、連想配列にて、[0]とし引き渡す事で、str処理などを気にせず、格納できる。
色々試したのだが、連想配列以外での受け渡しだとうまく受け取れないdictだったり、strだったり...typeが異なり、受け取りの処理が複雑かつ、面倒になりがちだった...

ひとまず、これで落ち着くと思う。

以上。

1
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0