フロントエンジニアでも
py がしたい
2013/03/22
 Tech Lab 3
Agenda
 •お前だれよ
 •python って何よ
 •python の開発環境
 •作ってみる
お前だれよ

 •Yamaguchi Eikichi
 •@__hage__
 •何でも屋 → 4月からフリーランス
 •http://dev.hageee.net
 •python は 2年ちょっと
https://twitter.com/yuchimiri/status/312351688382111745/photo/1
python の特長

  •シンプルな文法
  •最初からオブジェクト指向
  •手続き型みたいな書き方もできる
  •拡張が C/C++ でもかける
  •適当に書いても速い
  •OS の深いところまで触れる
  •最新は 3.3.x 系
  •仕事で使う & 最初の一歩は 2.7.x 系
活躍の場に見境がない python さん
python の文法
python の開発環境
python の開発環境

       •pythonbrew
       •virtualenv, virtualenvwrapper
       •easy_install, pip
       •SublimeText2


※インストール方法は事前資料を参考。
https://gist.github.com/glassesfactory/5192223
pythonbrew

  •システムとは別の python
  •バージョンの切り替え
  •色々入れてくれる
virtualenv, virtualenvwrapper

   •システムとは別のライブラリ環境
   •プロジェクトごとに必要なモジュール
   •virtualenvwrapper でもう少し使いやすく
easy_install, pip

   •ライブラリの管理
   •入れたり消したり、リストをだしたり
   •virtualenv と組み合わせることでプロジェクト環境を作る
モジュールの管理


インストール

$(techlab3) pip install flask




アンインストール

$(techlab3) pip uninstall flask




一覧

$(techlab3) pip freeze
Flask




         MVC のうち、Cに関わる部分をやってくれる。
    非常にシンプルにかけるため、ちょっとした API を構築する時便利。
これぐらい簡単




ルーティングとコントローラーが同時に出来る!


$ (project_name) python main.py

           で、実行してみる
作ってみる
Hello World!

               #!/usr/bin/env python
               # -*- coding: utf-8 -*-

               from flask import Flask


               app = Flask(__name__)


               @app.route('/')
               def index():
                   return "hell world"


               if __name__ == '__main__':
                   app.run()
テンプレート周り

 •jinja2 + pyjade
     jinja2 を jade 形式で記述

 •install
 $(techlab3) pip install pyjade




 •使えるようにする
 app = Flask(__name__)

 app.jinja_env.add_extension('pyjade.ext.jinja.PyJadeExtension')

 @app.route('/'):
     return render_template('index.jade')
書き方

      jade の基本構文




      変数とメソッド
書き方

  ステートメント
テンプレートの継承
  継承元




  拡張
mongodb




            ドキュメント指向データベース。
           RDBMS ではなく NoSQL に分類。



           レコードをテーブルに格納するのではなく
            構造データをJSON形式で表現する。
          構造データの集合体をコレクションと呼ぶ。
mongodb のメリットデメリット

 メリット
  •とても気軽に使える。モックレベルならさくさく。
  •単純なデータの I/O が速い
  •動的にフィールドを追加できる


 デメリット
  •MySQL などと違いデータの型指定が厳密でない
  •柔軟すぎるがゆえに事故が起こる
mongoengine 使おう


インストール

$(techlab3) pip install mongoengine




•フィールドの型指定
•mongodb をちょっと RDBMS の ORM っぽく扱える用になる。
つかってみる
 接続/切断
  from mongoengine import *


  con = connect('db_name')
  con.disconnect()


 モデル
  from datetime import datetime
  from mongoengine import *


  class Tweet(Document):
      sid = SequenceField(unique=True)
      text = StringField(required=True)
      created_at = DateTimeField(default=datetime.now)
      updated_at = DateTimeField(default=datetime.now)
つかってみる


新規作成                          取得
 #保存                           #コレクション取得
 tweet = Tweet(text='hage')    for tweet in Tweet.objects():
 tweet.save()                      logging.info(tweet.text)




更新                            削除

 hironori.text = 'boorin'      hironori.delete()
 hironori.save()
ちょっとチュートリアルっぽく
モデル定義




 from datetime import datetime
 from mongoengine import *


 class Tweet(Document):
     sid = SequenceField(unique=True)
     text = StringField(required=True)
     created_at = DateTimeField(default=datetime.now)
     updated_at = DateTimeField(default=datetime.now)
model.py


    •Tweet モデルを書く
    •db とのコネクションを管理する DBI を書く
ルーティング

  単純な CRUD を実装する上で
  以下のようなルーティングを定義する。



         •一覧 => / [GET]
         •詳細 => /1, /2, /3... [GET]
         •新規 => /new [GET]
         •保存 => / [POST]
         •更新 => / [PUT]
         •削除 => / [DELETE]
リクエストタイプに応じたレスポンス
   json を要求されたら json を返す。
   そうでなければ HTML を返す
   →レスポンスのファイルタイプが異なるだけで
     ほとんどの処理が同じになる場合が多いため。



  @app.route('/index.json', method=["GET"])
  @app.route('/', method=["GET"])
  def index():
      #リクエストが json だったら
      if request.headers['Content-Type'] ==
  'application/json':
          return #json 返す
      else:
          #そうでなければ html を返す。
          return render_template('index.jade')
db から引っ張り上げる
  事前に定義した DBI を使って
  mongodb との接続を確立しつつ、データをひっぱる。



      from model import db, Tweet

      with db:
          collection = Tweet.objects.all()
データの整形
  mongodb からのデータを
  そのまま json にしようとするといくつかのデータは型が
  存在しないと怒られるので整形する。


 def model_serializer(model):
     result = {}
     for k in model:
         val = model[k]
         if isinstance(val, (str, basestring, int, float)):
             result.setdefault(k, val)
         elif isinstance(val, list):
             l = [model_serializer(v) for v in val]
             result.setdefault(k, l)
         elif isinstance(val, dict):
             result.setdefault(k, model_serializer(val))
         elif isinstance(val, datetime):
             result.setdefault(k, val.strftime('%Y/%m/%d %H:%M:%S'))
         elif isinstance(val, Document):
             result.setdefault(k, model_serializer(val))
         elif isinstance(val, ObjectId):
             result.setdefault(k, str(val))
     return result
json にして返す
   python には 2.6 からデフォルトで
   json のパーサーが備わっているため
   特に細かいことを気にする必要はない。




          import json
          json.dumps({'hoge':'huga'})
データの保存

 フォームからのデータを引っ張ってきて
 モデルへ突っ込んで保存する。


  @app.route('/create', methods=["POST"])
  def create():
      data = request.form
      tweet = Tweet(text=data["text"])
      try:
           tweet.save()
      except Exception:
           print e
      serialized = modelSerializer(tweet)
      resData = json.dumps(serialized)
      return Response(resData, content_type="application/json",
  status=200)
データの削除




 @app.route('/<int:id>', methods=["DELETE"])
 def destroy(id):
     with db:
         try:
              tweet = Tweet.objects(sid=id).first().delete()
              datas = json.dumps({'id': tweet.sid})
         except:
              # raise
     return Response(datas, mimetype="application/json", status=200)
データの更新


  @app.route('/<int:id>', methods=["PUT"])
  def update(id):
      data = request.form
      with db:
          tweet = Tweet.objects(sid=id).first()
          tweet.text = data['text']
          tweet.updated_at = datetime.now()
          try:
               tweet.save()
          except Exception, e:
               print e
      serialized = model_serializer(tweet)
      resData = json.dumps(serialized)
      return Response(resData, mimetype="application/json", status=200)
オススメの本
オススメの本

Teclab3

  • 1.
  • 2.
    Agenda •お前だれよ •pythonって何よ •python の開発環境 •作ってみる
  • 3.
    お前だれよ •Yamaguchi Eikichi •@__hage__ •何でも屋 → 4月からフリーランス •http://dev.hageee.net •python は 2年ちょっと
  • 5.
  • 6.
    python の特長 •シンプルな文法 •最初からオブジェクト指向 •手続き型みたいな書き方もできる •拡張が C/C++ でもかける •適当に書いても速い •OS の深いところまで触れる •最新は 3.3.x 系 •仕事で使う & 最初の一歩は 2.7.x 系
  • 7.
  • 8.
  • 9.
  • 10.
    python の開発環境 •pythonbrew •virtualenv, virtualenvwrapper •easy_install, pip •SublimeText2 ※インストール方法は事前資料を参考。 https://gist.github.com/glassesfactory/5192223
  • 11.
    pythonbrew •システムとは別のpython •バージョンの切り替え •色々入れてくれる
  • 12.
    virtualenv, virtualenvwrapper •システムとは別のライブラリ環境 •プロジェクトごとに必要なモジュール •virtualenvwrapper でもう少し使いやすく
  • 13.
    easy_install, pip •ライブラリの管理 •入れたり消したり、リストをだしたり •virtualenv と組み合わせることでプロジェクト環境を作る
  • 14.
    モジュールの管理 インストール $(techlab3) pip installflask アンインストール $(techlab3) pip uninstall flask 一覧 $(techlab3) pip freeze
  • 15.
    Flask MVC のうち、Cに関わる部分をやってくれる。 非常にシンプルにかけるため、ちょっとした API を構築する時便利。
  • 16.
  • 17.
  • 18.
    Hello World! #!/usr/bin/env python # -*- coding: utf-8 -*- from flask import Flask app = Flask(__name__) @app.route('/') def index(): return "hell world" if __name__ == '__main__': app.run()
  • 19.
    テンプレート周り •jinja2 +pyjade jinja2 を jade 形式で記述 •install $(techlab3) pip install pyjade •使えるようにする app = Flask(__name__) app.jinja_env.add_extension('pyjade.ext.jinja.PyJadeExtension') @app.route('/'): return render_template('index.jade')
  • 20.
    書き方 jade の基本構文 変数とメソッド
  • 21.
  • 22.
  • 23.
    mongodb ドキュメント指向データベース。 RDBMS ではなく NoSQL に分類。 レコードをテーブルに格納するのではなく 構造データをJSON形式で表現する。 構造データの集合体をコレクションと呼ぶ。
  • 24.
    mongodb のメリットデメリット メリット •とても気軽に使える。モックレベルならさくさく。 •単純なデータの I/O が速い •動的にフィールドを追加できる デメリット •MySQL などと違いデータの型指定が厳密でない •柔軟すぎるがゆえに事故が起こる
  • 25.
    mongoengine 使おう インストール $(techlab3) pipinstall mongoengine •フィールドの型指定 •mongodb をちょっと RDBMS の ORM っぽく扱える用になる。
  • 26.
    つかってみる 接続/切断 from mongoengine import * con = connect('db_name') con.disconnect() モデル from datetime import datetime from mongoengine import * class Tweet(Document): sid = SequenceField(unique=True) text = StringField(required=True) created_at = DateTimeField(default=datetime.now) updated_at = DateTimeField(default=datetime.now)
  • 27.
    つかってみる 新規作成 取得 #保存 #コレクション取得 tweet = Tweet(text='hage') for tweet in Tweet.objects(): tweet.save() logging.info(tweet.text) 更新 削除 hironori.text = 'boorin' hironori.delete() hironori.save()
  • 28.
  • 29.
    モデル定義 from datetimeimport datetime from mongoengine import * class Tweet(Document): sid = SequenceField(unique=True) text = StringField(required=True) created_at = DateTimeField(default=datetime.now) updated_at = DateTimeField(default=datetime.now)
  • 30.
    model.py •Tweet モデルを書く •db とのコネクションを管理する DBI を書く
  • 31.
    ルーティング 単純なCRUD を実装する上で 以下のようなルーティングを定義する。 •一覧 => / [GET] •詳細 => /1, /2, /3... [GET] •新規 => /new [GET] •保存 => / [POST] •更新 => / [PUT] •削除 => / [DELETE]
  • 32.
    リクエストタイプに応じたレスポンス json を要求されたら json を返す。 そうでなければ HTML を返す →レスポンスのファイルタイプが異なるだけで ほとんどの処理が同じになる場合が多いため。 @app.route('/index.json', method=["GET"]) @app.route('/', method=["GET"]) def index(): #リクエストが json だったら if request.headers['Content-Type'] == 'application/json': return #json 返す else: #そうでなければ html を返す。 return render_template('index.jade')
  • 33.
    db から引っ張り上げる 事前に定義した DBI を使って mongodb との接続を確立しつつ、データをひっぱる。 from model import db, Tweet with db: collection = Tweet.objects.all()
  • 34.
    データの整形 mongodbからのデータを そのまま json にしようとするといくつかのデータは型が 存在しないと怒られるので整形する。 def model_serializer(model): result = {} for k in model: val = model[k] if isinstance(val, (str, basestring, int, float)): result.setdefault(k, val) elif isinstance(val, list): l = [model_serializer(v) for v in val] result.setdefault(k, l) elif isinstance(val, dict): result.setdefault(k, model_serializer(val)) elif isinstance(val, datetime): result.setdefault(k, val.strftime('%Y/%m/%d %H:%M:%S')) elif isinstance(val, Document): result.setdefault(k, model_serializer(val)) elif isinstance(val, ObjectId): result.setdefault(k, str(val)) return result
  • 35.
    json にして返す python には 2.6 からデフォルトで json のパーサーが備わっているため 特に細かいことを気にする必要はない。 import json json.dumps({'hoge':'huga'})
  • 36.
    データの保存 フォームからのデータを引っ張ってきて モデルへ突っ込んで保存する。 @app.route('/create', methods=["POST"]) def create(): data = request.form tweet = Tweet(text=data["text"]) try: tweet.save() except Exception: print e serialized = modelSerializer(tweet) resData = json.dumps(serialized) return Response(resData, content_type="application/json", status=200)
  • 37.
    データの削除 @app.route('/<int:id>', methods=["DELETE"]) def destroy(id): with db: try: tweet = Tweet.objects(sid=id).first().delete() datas = json.dumps({'id': tweet.sid}) except: # raise return Response(datas, mimetype="application/json", status=200)
  • 38.
    データの更新 @app.route('/<int:id>',methods=["PUT"]) def update(id): data = request.form with db: tweet = Tweet.objects(sid=id).first() tweet.text = data['text'] tweet.updated_at = datetime.now() try: tweet.save() except Exception, e: print e serialized = model_serializer(tweet) resData = json.dumps(serialized) return Response(resData, mimetype="application/json", status=200)
  • 40.
  • 41.