SlideShare a Scribd company logo
1 of 28
Download to read offline
Djangoで黒魔術
@whosaysni
自己紹介
増田 泰 (@whosaysni)!
http://whosaysni.jp/!
!
某バイオベンチャー勤務ですが…!
!
一般社団法人PyConJP理事!
PyConJP 9/13-15 CFP中!
http://2014.pycon.jp/!
!
ろうじん老神.py 幹事!
https://sites.google.com/site/oikamipy/
Django
Django
もうすぐ9歳!
0.95 Djangoドキュメントが和訳されるw
0.98 内部コードがUnicode化される
1.0 メジャーリリース
1.2 マルチDBに対応
1.3 クラスベースビュー、さようならmod_python
1.4 project/app のレイアウトが変更される
1.6 Userを置き換えられるようになった(らしい)
1.7 スキーママイグレーションが組み込まれる(予定)
おしながき
• {% with %} タグの変態的な誤った使い方
• DjangoのマルチDBをハックする
{% with %}
{% with %} タグ
• テンプレート中で変数を束縛する
• ブロック内がスコープ
• スコープ内の {% include %} に波及
する
• ネスト可
{%	 with	 a='foo'	 b='bar'	 %}

!
Outside	 nest:{{	 a	 }}/{{	 b	 }}/{{	 c	 }}.

!
{%	 with	 c=a	 b='baz'	 %}

!
Inside	 nest:	 {{	 a	 }}/{{	 b	 }}/{{	 c	 }}.

!
{%	 endwith	 %}

!
{%	 endwith	 %}
!
Outside	 nest:	 foo/bar/.

!
Inside	 nest:	 foo/baz/foo.
{% with %} の構文
{%	 with	 a=123	 c='defg'	 e=hij	 ...	 %}
タグ トークン列
トークン トークン トークン
a=123
a	 as	 123
古い形式の
キーワード引数
キーワード引数
キー 引数
{% with %} の実装(1)
@register.tag('with')

def	 do_with(parser,	 token):

	 	 	 	 ...

	 	 	 	 bits	 =	 token.split_contents()

	 	 	 	 remaining_bits	 =	 bits[1:]

	 	 	 	 extra_context	 =	 token_kwargs(remaining_bits,	 parser,	 support_legacy=True)

	 	 	 	 if	 not	 extra_context:

	 	 	 	 	 	 	 	 raise	 TemplateSyntaxError("%r	 expected	 at	 least	 one	 variable	 "

	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 "assignment"	 %	 bits[0])

	 	 	 	 if	 remaining_bits:

	 	 	 	 	 	 	 	 raise	 TemplateSyntaxError("%r	 received	 an	 invalid	 token:	 %r"	 %

	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 (bits[0],	 remaining_bits[0]))

	 	 	 	 nodelist	 =	 parser.parse(('endwith',))

	 	 	 	 parser.delete_first_token()

	 	 	 	 return	 WithNode(None,	 None,	 nodelist,	 extra_context=extra_context)

トークン列を取り出す
テンプレートの解析中に with タグを見つけたときの処理
各トークンをキーワード引数
として解析する
レンダリングノードを作成する
endwith までを子ノードにする
{% with %} の実装(2)
class	 WithNode(Node):

	 	 	 	 def	 __init__(self,	 var,	 name,	 nodelist,	 extra_context=None):

	 	 	 	 	 	 	 	 self.nodelist	 =	 nodelist

	 	 	 	 	 	 	 	 #	 var	 and	 name	 are	 legacy	 attributes,	 being	 left	 in	 case	 they	 are	 used

	 	 	 	 	 	 	 	 #	 by	 third-party	 subclasses	 of	 this	 Node.

	 	 	 	 	 	 	 	 self.extra_context	 =	 extra_context	 or	 {}

	 	 	 	 	 	 	 	 if	 name:

	 	 	 	 	 	 	 	 	 	 	 	 self.extra_context[name]	 =	 var

!
	 	 	 	 def	 __repr__(self):

	 	 	 	 	 	 	 	 return	 "<WithNode>"

!
	 	 	 	 def	 render(self,	 context):

	 	 	 	 	 	 	 	 values	 =	 dict([(key,	 val.resolve(context))	 for	 key,	 val	 in

	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 six.iteritems(self.extra_context)])

	 	 	 	 	 	 	 	 context.update(values)

	 	 	 	 	 	 	 	 output	 =	 self.nodelist.render(context)

	 	 	 	 	 	 	 	 context.pop()

	 	 	 	 	 	 	 	 return	 output

子ノード(ブロックの内容)
キーワード引数
互換性用のコード
キーワード引数の値を解決して辞書にする
子ノードをレンダリング
コンテキストをスタック
コンテキストを復帰
コンテキスト
• インタフェースは辞書
• データ構造は辞書のスタック
• 一番上から順に検索する
context['color'] -> 'blue'
context['number'] -> 2
context['food'] -> 'spam'
Context
number=42
food='spam'
animal='duck'
color='blue'
number=2
dict
dict
dict
• 要するに、 {% with %} タグは、一時的にコンテ
キストに辞書を積んでブロックをレンダするタグ
• スコープの外の同名の変数は見えなくなる
• with のキーワード引数は、ブロックのレンダ直
前に解決される
ということで・・・
変#1: デフォルト値
• コンテキストに username が
あるかどうかわからない
• username がなければ「名無
し」さん
• username があればその値
{{	 username	 }}	 	 	 これはダメ
{{	 username|default:'名無し'	 }}	 	 	 一応OK
<span>ようこそ{{	 username|default:'名無
し'	 }}さん</span>

!
...

!
<h1>{{	 username|default:'名無し'	 }}さん
のプロフィール</h1>

!
...

!
<h2>{{	 username|default:'名無し'	 }}さん
へのおすすめ</h2>

!
....

(#`Д́)ノノ┻┻;:'、・゙ヤッテラレルカ!
変#1: デフォルト値
{%	 with	 username=username|default:'名無し'	 %}

!
<span>ようこそ{{	 username	 }}さん</span>

!
...

!
<h1>{{	 username	 }}さんのプロフィール</h1>

!
...

!
<h2>{{	 username	 }}さんへのおすすめ</h2>

!
....

!
{%	 endwith	 %}
• コンテキスト変数を確実に埋
めておきたいときは、{% with
%}でデフォルト値をオーバラ
イドしたブロックをつくる
• 同じ変数を何度も参照したい
ときにも、 {% with %} が有
効
変#2: {% include %}の悪用
Hello	 {{	 foo	 }}.
• {% include %} は、レンダ時
にテンプレートを展開する(実
際には、include 対象をレン
ダして結果を挿入する)
• レンダ対象にはコンテキスト
がそのまま渡る
{%	 with	 foo='bar'	 %}

!
{%	 include	 "included.html"	 %}

!
{%	 endwith	 %}
Hello	 bar.
変#2: {% include %}の利用
{{	 field.label_tag	 }}

<p	 class="tertiary-text-secondary">

	 	 {{	 field.help_text	 }}

</p>

<div>

	 	 {%	 with	 field_type=type|default:""	 %}

	 	 <div	 class="input-control"	 ...>

	 	 	 	 {%	 ifequal	 field_type	 ""	 %}

	 	 	 	 {{	 field	 }}

	 	 	 	 {%	 endifequal	 %}

	 	 	 	 {%	 ifequal	 field_type	 "text"	 %}

	 	 	 	 {{	 field	 }}

	 	 	 	 <button	 type="button"	 class="btn-clear"></button>

	 	 	 	 {%	 endifequal	 %}

	 	 	 	 {%	 ifequal	 field_type	 "password"	 %}

	 	 	 	 {{	 field	 }}

	 	 	 	 <button	 type="button"	 	 class="btn-reveal"></button>

	 	 	 	 {%	 endifequal	 %}

	 	 	 	 {%	 ifequal	 field_type	 "switch"	 %}

	 	 	 	 <label>

	 	 	 	 	 	 {{	 field	 }}

	 	 	 	 	 	 <span	 class="check"></span>

	 	 	 	 </label>

	 	 	 	 {%	 endifequal	 %}

	 	 	 	 <span	 class="tertiary-text	 text-alert">

	 	 	 	 	 	 {{	 field.errors.as_text	 }}

	 	 	 	 </span>

	 	 </div>

	 	 {%	 endwith	 %}

</div>
• フォームフィールドをカスタ
マイズしたいとき
• 正攻法は widget のサブクラ
ス化(めんどくさい)
• 各フィールドタイプで分岐す
るテンプレートを作っておく
field.html
変#2: {% include %}の利用
<div	 class="container	 padding10">

	 	 <h1>Add	 user</h1>

	 	 <div	 class="padding10">

	 	 	 	 <form	 method="POST"	 action="{%	 url	 'user_add'	 %}">

	 	 	 	 	 	 {%	 csrf_token	 %}

	 	 	 	 	 	 <fieldset>

	 	 	 	 	 	 	 	 {%	 with	 field=form.is_superuser	 type='switch'	 %}{%	 include	 "field.html"	 %}{%	 endwith	 %}

	 	 	 	 	 	 	 	 {%	 with	 field=form.is_active	 type='switch'	 %}{%	 include	 "field.html"	 %}{%	 endwith	 %}

	 	 	 	 	 	 	 	 {%	 with	 field=form.username	 type='text'	 %}{%	 include	 "field.html"	 %}{%	 endwith	 %}

	 	 	 	 	 	 	 	 {%	 with	 field=form.password	 type='password'	 %}{%	 include	 "field.html"	 %}{%	 endwith	 %}

	 	 	 	 	 	 	 	 {%	 with	 field=form.email	 type='text'	 %}{%	 include	 "field.html"	 %}{%	 endwith	 %}

	 	 	 	 	 	 	 	 {%	 with	 field=form.first_name	 type='text'	 %}{%	 include	 "field.html"	 %}{%	 endwith	 %}

	 	 	 	 	 	 	 	 {%	 with	 field=form.last_name	 type='text'	 %}{%	 include	 "field.html"	 %}{%	 endwith	 %}

	 	 	 	 	 	 </fieldset>

	 	 	 	 	 	 <div	 class="button-group">

	  <input	 type="submit"	 value="Add"	 />

	 	 	 	 	 	 </div>

	 	 	 	 </form>

	 	 </div>

</div>
テンプレート2つで、フィールドをカスタマイズできる
Multi-DB
Django Multi-DB
• 1.2で導入された
• バックエンドDBのマスタ
スレーブ化、シャーディン
グ、レプリケーションを可
能にする
• モデル単位でDBのルーティ
ングができる
Django
App
Replicate/Partition
RO
Access
RW
Access
Multi-DBの構成
• settings に静的に定義
• 名前で区別する
• DBのパラメタは辞書
• using() またはデータベー
スルータで制御する
BE_PG	 =	 'django.db.backends.postgresql_psycopg2'

BE_MY	 =	 'django.db.backends.mysql'

DATABASES	 =	 {

	 	 	 	 'default':	 {

	 	 	 	 	 	 	 	 'NAME':	 'master_db',

	 	 	 	 	 	 	 	 'ENGINE':	 BE_PG,

	 	 	 	 	 	 	 	 'USER':	 'master_user',

	 	 	 	 	 	 	 	 'PASSWORD':	 'boo	 hoo	 woo'

	 	 	 	 },

	 	 	 	 'replicon':	 {

	 	 	 	 	 	 	 	 'NAME':	 'replicon_db',

	 	 	 	 	 	 	 	 'ENGINE':	 BE_MY,

	 	 	 	 	 	 	 	 'USER':	 'replicon_user',

	 	 	 	 	 	 	 	 'PASSWORD':	 'let	 it	 go'

	 	 	 	 }

}
#	 名前でデータベースを指定する

User.objects.using('users').get(...)

!
#	 データベースルータを使う

class	 MyDbRouter(object):

	 	 	 	 def	 db_for_read(self,	 model,	 **kw):

	 	 	 	 	 	 	 	 if	 ...:

	 	 	 	 	 	 	 	 	 	 	 return	 'replicon'

DATABASE_ROUTERS	 =	 ['foo.bar.MyDbRouter',...]
Multi-DBの実装
• データベース名は文字列
• django.db.connections
を使ってDB接続を取り出
している
• connections は辞書ライ
クなインタフェースを持つ
ConnectionHandlerイン
スタンス
from	
 django.db	
 import	
 connections	
 
!
class	
 QuerySet(object):	
 
	
 	
 	
 	
 """	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 
	
 	
 	
 	
 Represents	
 a	
 lazy	
 database	
 lookup	
 for	
 a	
 set	
 of	
 objects.	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 
	
 	
 	
 	
 """	
 
	
 	
 	
 	
 def	
 __init__(self,	
 model=None,	
 query=None,	
 using=None):	
 
	
 	
 	
 	
 	
 	
 	
 	
 self.model	
 =	
 model	
 
	
 	
 	
 	
 	
 	
 	
 	
 self._db	
 =	
 using	
 
	
 	
 	
 	
 	
 	
 	
 	
 self.query	
 =	
 query	
 or	
 sql.Query(self.model)	
 
	
 	
 	
 	
 	
 	
 	
 	
 ...	
 
!
	
 	
 	
 	
 def	
 ...	
 
	
 	
 	
 	
 	
 	
 	
 	
 connection	
 =	
 connections[self.db]	
 
django.db.models.query
from	
 django.db.utils	
 import	
 ConnectionHandler	
 
connections	
 =	
 ConnectionHandler()	
 
django.db.__init__
Multi-DBの実装
• ConnectionHandlerはDB
設定とコネクションプール
をキャッシュしているらし
い
• __getitem__ で何かゴニョ
ゴニョして取り出している
模様
class	
 ConnectionHandler(object):	
 
	
 	
 	
 	
 def	
 __init__(self,	
 databases=None):	
 
	
 	
 	
 	
 	
 	
 	
 	
 self._databases	
 =	
 databases	
 
	
 	
 	
 	
 	
 	
 	
 	
 self._connections	
 =	
 local()	
 
!
	
 	
 	
 	
 ...	
 
!
	
 	
 	
 	
 def	
 __getitem__(self,	
 alias):	
 
	
 	
 	
 	
 	
 	
 	
 	
 if	
 hasattr(self._connections,	
 alias):	
 
	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 	
 return	
 getattr(self._connections,	
 alias)	
 
!
	
 	
 	
 	
 	
 	
 	
 	
 self.ensure_defaults(alias)	
 
	
 	
 	
 	
 	
 	
 	
 	
 db	
 =	
 self.databases[alias]	
 
	
 	
 	
 	
 	
 	
 	
 	
 backend	
 =	
 load_backend(db['ENGINE'])	
 
	
 	
 	
 	
 	
 	
 	
 	
 conn	
 =	
 backend.DatabaseWrapper(db,	
 alias)	
 
	
 	
 	
 	
 	
 	
 	
 	
 setattr(self._connections,	
 alias,	
 conn)	
 
	
 	
 	
 	
 	
 	
 	
 	
 return	
 conn	
 
django.db.utils
• と、いうことは、ConnectionHandlerの実装を
動的に差し替えてやれば、ランタイムでDBの設
定を切り替えられるはず
• DBの設定はPythonオブジェクト→Djangoのモ
デルにできるはず
やってみました
https://gist.github.com/whosaysni/11361218
Thanks!

More Related Content

What's hot

MT meets PHP - PHP conference Kansai 2013
MT meets PHP - PHP conference Kansai 2013MT meets PHP - PHP conference Kansai 2013
MT meets PHP - PHP conference Kansai 2013
純生 野田
 
PerlとSQLのいろいろ
PerlとSQLのいろいろPerlとSQLのいろいろ
PerlとSQLのいろいろ
Takuya Tsuchida
 
脱コピペ!デザイナーにもわかるPHPとWP_Query
脱コピペ!デザイナーにもわかるPHPとWP_Query脱コピペ!デザイナーにもわかるPHPとWP_Query
脱コピペ!デザイナーにもわかるPHPとWP_Query
Hidekazu Ishikawa
 
俺のフックがこんなに簡単なわけがない。
俺のフックがこんなに簡単なわけがない。俺のフックがこんなに簡単なわけがない。
俺のフックがこんなに簡単なわけがない。
Hishikawa Takuro
 
はじめてのCouch db
はじめてのCouch dbはじめてのCouch db
はじめてのCouch db
Eiji Kuroda
 
WordPressで提供するWeb API
WordPressで提供するWeb APIWordPressで提供するWeb API
WordPressで提供するWeb API
Yuko Toriyama
 

What's hot (18)

MT meets PHP
MT meets PHPMT meets PHP
MT meets PHP
 
Inside Movable Type
Inside Movable TypeInside Movable Type
Inside Movable Type
 
MT meets PHP - PHP conference Kansai 2013
MT meets PHP - PHP conference Kansai 2013MT meets PHP - PHP conference Kansai 2013
MT meets PHP - PHP conference Kansai 2013
 
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
「スピード」と「品質」を実現するPHP開発チームの取り組み~AngularJS+FuelPHP+AspectMock~
 
やはりお前らのMTMLは間違っている!
やはりお前らのMTMLは間違っている!やはりお前らのMTMLは間違っている!
やはりお前らのMTMLは間違っている!
 
3時間濃縮CakePHP2.1 in PHPカンファレンス北海道2012
3時間濃縮CakePHP2.1 in PHPカンファレンス北海道20123時間濃縮CakePHP2.1 in PHPカンファレンス北海道2012
3時間濃縮CakePHP2.1 in PHPカンファレンス北海道2012
 
PHP Object Injection入門
PHP Object Injection入門PHP Object Injection入門
PHP Object Injection入門
 
PerlとSQLのいろいろ
PerlとSQLのいろいろPerlとSQLのいろいろ
PerlとSQLのいろいろ
 
脱コピペ!デザイナーにもわかるPHPとWP_Query
脱コピペ!デザイナーにもわかるPHPとWP_Query脱コピペ!デザイナーにもわかるPHPとWP_Query
脱コピペ!デザイナーにもわかるPHPとWP_Query
 
WordPress のキャッシュ機構
WordPress のキャッシュ機構WordPress のキャッシュ機構
WordPress のキャッシュ機構
 
俺のフックがこんなに簡単なわけがない。
俺のフックがこんなに簡単なわけがない。俺のフックがこんなに簡単なわけがない。
俺のフックがこんなに簡単なわけがない。
 
はじめてのCouch db
はじめてのCouch dbはじめてのCouch db
はじめてのCouch db
 
WordPressで提供するWeb API
WordPressで提供するWeb APIWordPressで提供するWeb API
WordPressで提供するWeb API
 
Yahoo!ボックスAPI Hackathon向け資料
Yahoo!ボックスAPI Hackathon向け資料Yahoo!ボックスAPI Hackathon向け資料
Yahoo!ボックスAPI Hackathon向け資料
 
Tritonn から Elasticsearch への移行話
Tritonn から Elasticsearch への移行話Tritonn から Elasticsearch への移行話
Tritonn から Elasticsearch への移行話
 
Yahoo!ボックスAPI Hackday資料
Yahoo!ボックスAPI Hackday資料Yahoo!ボックスAPI Hackday資料
Yahoo!ボックスAPI Hackday資料
 
BPStudy32 CouchDB 再入門
BPStudy32 CouchDB 再入門BPStudy32 CouchDB 再入門
BPStudy32 CouchDB 再入門
 
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
仕事の手離れを良くする手段としての、静的検査のあるテンプレートエンジン (YATT::Lite talk at 2014 テンプレートエンジンNight)
 

Viewers also liked (6)

オープンCAEとPython
オープンCAEとPythonオープンCAEとPython
オープンCAEとPython
 
GAEでスパイクを捌く
GAEでスパイクを捌くGAEでスパイクを捌く
GAEでスパイクを捌く
 
Python 2/3コード共存戦略 #osakapy
Python 2/3コード共存戦略 #osakapyPython 2/3コード共存戦略 #osakapy
Python 2/3コード共存戦略 #osakapy
 
Code_Saturne流体解析入門講習会 講習会資料
Code_Saturne流体解析入門講習会 講習会資料Code_Saturne流体解析入門講習会 講習会資料
Code_Saturne流体解析入門講習会 講習会資料
 
オープンソースの CFD ソフトウェア SU2 のチュートリアルをやってみた
オープンソースの CFD ソフトウェア SU2 のチュートリアルをやってみたオープンソースの CFD ソフトウェア SU2 のチュートリアルをやってみた
オープンソースの CFD ソフトウェア SU2 のチュートリアルをやってみた
 
OpenFOAM の Function Object 機能について
OpenFOAM の Function Object 機能についてOpenFOAM の Function Object 機能について
OpenFOAM の Function Object 機能について
 

Similar to Django boodoo

速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
Kazunari Hara
 
Rails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3editionRails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3edition
Satomi Tsujita
 
Mojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてるMojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてる
jamadam
 

Similar to Django boodoo (20)

環境構築から始めるDjangoチュートリアル
環境構築から始めるDjangoチュートリアル環境構築から始めるDjangoチュートリアル
環境構築から始めるDjangoチュートリアル
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
 
Teclab3
Teclab3Teclab3
Teclab3
 
Djangoフレームワークの紹介
Djangoフレームワークの紹介Djangoフレームワークの紹介
Djangoフレームワークの紹介
 
OSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニックOSSから学ぶSwift実践テクニック
OSSから学ぶSwift実践テクニック
 
eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜eZ Publish勉強会9月〜テンプレート言語〜
eZ Publish勉強会9月〜テンプレート言語〜
 
Go言語入門者が Webアプリケーション を作ってみた話 #devfest #gdgkyoto
Go言語入門者が Webアプリケーション を作ってみた話 #devfest #gdgkyotoGo言語入門者が Webアプリケーション を作ってみた話 #devfest #gdgkyoto
Go言語入門者が Webアプリケーション を作ってみた話 #devfest #gdgkyoto
 
Grails 2.0.0.M1の話
Grails 2.0.0.M1の話 Grails 2.0.0.M1の話
Grails 2.0.0.M1の話
 
Djangoによるスマホアプリバックエンドの実装
Djangoによるスマホアプリバックエンドの実装Djangoによるスマホアプリバックエンドの実装
Djangoによるスマホアプリバックエンドの実装
 
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピングpi-15. カプセル化, MVCモデル, オブジェクトのマッピング
pi-15. カプセル化, MVCモデル, オブジェクトのマッピング
 
ScaLa+Liftとか
ScaLa+LiftとかScaLa+Liftとか
ScaLa+Liftとか
 
Backbone.js
Backbone.jsBackbone.js
Backbone.js
 
Functional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.jsFunctional JavaScript with Lo-Dash.js
Functional JavaScript with Lo-Dash.js
 
Rails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3editionRails初心者レッスン lesson3 3edition
Rails初心者レッスン lesson3 3edition
 
CodeIgniter入門
CodeIgniter入門CodeIgniter入門
CodeIgniter入門
 
React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門React.jsでクライアントサイドなWebアプリ入門
React.jsでクライアントサイドなWebアプリ入門
 
Using Dancer
Using DancerUsing Dancer
Using Dancer
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
Mojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてるMojoliciousをウェブ制作現場で使ってみてる
Mojoliciousをウェブ制作現場で使ってみてる
 
DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法
DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法
DEV-010_エンプラ系業務 Web アプリ開発に効く! 実践的 SPA 型モダン Web アプリ開発の選択手法
 

More from 泰 増田

More from 泰 増田 (8)

PlaySQLAlchemyORM2017.key
PlaySQLAlchemyORM2017.keyPlaySQLAlchemyORM2017.key
PlaySQLAlchemyORM2017.key
 
PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門
 
SQLAlchemy Primer
SQLAlchemy PrimerSQLAlchemy Primer
SQLAlchemy Primer
 
Taming robotframework
Taming robotframeworkTaming robotframework
Taming robotframework
 
Open bio2004 biopython
Open bio2004 biopythonOpen bio2004 biopython
Open bio2004 biopython
 
Python languageupdate (2004)
Python languageupdate (2004)Python languageupdate (2004)
Python languageupdate (2004)
 
Robot Framework (のSelenium2Libraryのお話)
Robot Framework (のSelenium2Libraryのお話)Robot Framework (のSelenium2Libraryのお話)
Robot Framework (のSelenium2Libraryのお話)
 
wxPython入門(大阪Pythonユーザの集まり2014/03)
wxPython入門(大阪Pythonユーザの集まり2014/03)wxPython入門(大阪Pythonユーザの集まり2014/03)
wxPython入門(大阪Pythonユーザの集まり2014/03)
 

Django boodoo

  • 2. 自己紹介 増田 泰 (@whosaysni)! http://whosaysni.jp/! ! 某バイオベンチャー勤務ですが…! ! 一般社団法人PyConJP理事! PyConJP 9/13-15 CFP中! http://2014.pycon.jp/! ! ろうじん老神.py 幹事! https://sites.google.com/site/oikamipy/
  • 6. 0.95 Djangoドキュメントが和訳されるw 0.98 内部コードがUnicode化される 1.0 メジャーリリース 1.2 マルチDBに対応 1.3 クラスベースビュー、さようならmod_python 1.4 project/app のレイアウトが変更される 1.6 Userを置き換えられるようになった(らしい) 1.7 スキーママイグレーションが組み込まれる(予定)
  • 7. おしながき • {% with %} タグの変態的な誤った使い方 • DjangoのマルチDBをハックする
  • 9. {% with %} タグ • テンプレート中で変数を束縛する • ブロック内がスコープ • スコープ内の {% include %} に波及 する • ネスト可 {% with a='foo' b='bar' %} ! Outside nest:{{ a }}/{{ b }}/{{ c }}. ! {% with c=a b='baz' %} ! Inside nest: {{ a }}/{{ b }}/{{ c }}. ! {% endwith %} ! {% endwith %} ! Outside nest: foo/bar/. ! Inside nest: foo/baz/foo.
  • 10. {% with %} の構文 {% with a=123 c='defg' e=hij ... %} タグ トークン列 トークン トークン トークン a=123 a as 123 古い形式の キーワード引数 キーワード引数 キー 引数
  • 11. {% with %} の実装(1) @register.tag('with') def do_with(parser, token): ... bits = token.split_contents() remaining_bits = bits[1:] extra_context = token_kwargs(remaining_bits, parser, support_legacy=True) if not extra_context: raise TemplateSyntaxError("%r expected at least one variable " "assignment" % bits[0]) if remaining_bits: raise TemplateSyntaxError("%r received an invalid token: %r" % (bits[0], remaining_bits[0])) nodelist = parser.parse(('endwith',)) parser.delete_first_token() return WithNode(None, None, nodelist, extra_context=extra_context) トークン列を取り出す テンプレートの解析中に with タグを見つけたときの処理 各トークンをキーワード引数 として解析する レンダリングノードを作成する endwith までを子ノードにする
  • 12. {% with %} の実装(2) class WithNode(Node): def __init__(self, var, name, nodelist, extra_context=None): self.nodelist = nodelist # var and name are legacy attributes, being left in case they are used # by third-party subclasses of this Node. self.extra_context = extra_context or {} if name: self.extra_context[name] = var ! def __repr__(self): return "<WithNode>" ! def render(self, context): values = dict([(key, val.resolve(context)) for key, val in six.iteritems(self.extra_context)]) context.update(values) output = self.nodelist.render(context) context.pop() return output 子ノード(ブロックの内容) キーワード引数 互換性用のコード キーワード引数の値を解決して辞書にする 子ノードをレンダリング コンテキストをスタック コンテキストを復帰
  • 13. コンテキスト • インタフェースは辞書 • データ構造は辞書のスタック • 一番上から順に検索する context['color'] -> 'blue' context['number'] -> 2 context['food'] -> 'spam' Context number=42 food='spam' animal='duck' color='blue' number=2 dict dict dict
  • 14. • 要するに、 {% with %} タグは、一時的にコンテ キストに辞書を積んでブロックをレンダするタグ • スコープの外の同名の変数は見えなくなる • with のキーワード引数は、ブロックのレンダ直 前に解決される
  • 16. 変#1: デフォルト値 • コンテキストに username が あるかどうかわからない • username がなければ「名無 し」さん • username があればその値 {{ username }} これはダメ {{ username|default:'名無し' }} 一応OK <span>ようこそ{{ username|default:'名無 し' }}さん</span> ! ... ! <h1>{{ username|default:'名無し' }}さん のプロフィール</h1> ! ... ! <h2>{{ username|default:'名無し' }}さん へのおすすめ</h2> ! .... (#`Д́)ノノ┻┻;:'、・゙ヤッテラレルカ!
  • 17. 変#1: デフォルト値 {% with username=username|default:'名無し' %} ! <span>ようこそ{{ username }}さん</span> ! ... ! <h1>{{ username }}さんのプロフィール</h1> ! ... ! <h2>{{ username }}さんへのおすすめ</h2> ! .... ! {% endwith %} • コンテキスト変数を確実に埋 めておきたいときは、{% with %}でデフォルト値をオーバラ イドしたブロックをつくる • 同じ変数を何度も参照したい ときにも、 {% with %} が有 効
  • 18. 変#2: {% include %}の悪用 Hello {{ foo }}. • {% include %} は、レンダ時 にテンプレートを展開する(実 際には、include 対象をレン ダして結果を挿入する) • レンダ対象にはコンテキスト がそのまま渡る {% with foo='bar' %} ! {% include "included.html" %} ! {% endwith %} Hello bar.
  • 19. 変#2: {% include %}の利用 {{ field.label_tag }} <p class="tertiary-text-secondary"> {{ field.help_text }} </p> <div> {% with field_type=type|default:"" %} <div class="input-control" ...> {% ifequal field_type "" %} {{ field }} {% endifequal %} {% ifequal field_type "text" %} {{ field }} <button type="button" class="btn-clear"></button> {% endifequal %} {% ifequal field_type "password" %} {{ field }} <button type="button" class="btn-reveal"></button> {% endifequal %} {% ifequal field_type "switch" %} <label> {{ field }} <span class="check"></span> </label> {% endifequal %} <span class="tertiary-text text-alert"> {{ field.errors.as_text }} </span> </div> {% endwith %} </div> • フォームフィールドをカスタ マイズしたいとき • 正攻法は widget のサブクラ ス化(めんどくさい) • 各フィールドタイプで分岐す るテンプレートを作っておく field.html
  • 20. 変#2: {% include %}の利用 <div class="container padding10"> <h1>Add user</h1> <div class="padding10"> <form method="POST" action="{% url 'user_add' %}"> {% csrf_token %} <fieldset> {% with field=form.is_superuser type='switch' %}{% include "field.html" %}{% endwith %} {% with field=form.is_active type='switch' %}{% include "field.html" %}{% endwith %} {% with field=form.username type='text' %}{% include "field.html" %}{% endwith %} {% with field=form.password type='password' %}{% include "field.html" %}{% endwith %} {% with field=form.email type='text' %}{% include "field.html" %}{% endwith %} {% with field=form.first_name type='text' %}{% include "field.html" %}{% endwith %} {% with field=form.last_name type='text' %}{% include "field.html" %}{% endwith %} </fieldset> <div class="button-group"> <input type="submit" value="Add" /> </div> </form> </div> </div> テンプレート2つで、フィールドをカスタマイズできる
  • 22. Django Multi-DB • 1.2で導入された • バックエンドDBのマスタ スレーブ化、シャーディン グ、レプリケーションを可 能にする • モデル単位でDBのルーティ ングができる Django App Replicate/Partition RO Access RW Access
  • 23. Multi-DBの構成 • settings に静的に定義 • 名前で区別する • DBのパラメタは辞書 • using() またはデータベー スルータで制御する BE_PG = 'django.db.backends.postgresql_psycopg2' BE_MY = 'django.db.backends.mysql' DATABASES = { 'default': { 'NAME': 'master_db', 'ENGINE': BE_PG, 'USER': 'master_user', 'PASSWORD': 'boo hoo woo' }, 'replicon': { 'NAME': 'replicon_db', 'ENGINE': BE_MY, 'USER': 'replicon_user', 'PASSWORD': 'let it go' } } # 名前でデータベースを指定する User.objects.using('users').get(...) ! # データベースルータを使う class MyDbRouter(object): def db_for_read(self, model, **kw): if ...: return 'replicon' DATABASE_ROUTERS = ['foo.bar.MyDbRouter',...]
  • 24. Multi-DBの実装 • データベース名は文字列 • django.db.connections を使ってDB接続を取り出 している • connections は辞書ライ クなインタフェースを持つ ConnectionHandlerイン スタンス from django.db import connections ! class QuerySet(object): """ Represents a lazy database lookup for a set of objects. """ def __init__(self, model=None, query=None, using=None): self.model = model self._db = using self.query = query or sql.Query(self.model) ... ! def ... connection = connections[self.db] django.db.models.query from django.db.utils import ConnectionHandler connections = ConnectionHandler() django.db.__init__
  • 25. Multi-DBの実装 • ConnectionHandlerはDB 設定とコネクションプール をキャッシュしているらし い • __getitem__ で何かゴニョ ゴニョして取り出している 模様 class ConnectionHandler(object): def __init__(self, databases=None): self._databases = databases self._connections = local() ! ... ! def __getitem__(self, alias): if hasattr(self._connections, alias): return getattr(self._connections, alias) ! self.ensure_defaults(alias) db = self.databases[alias] backend = load_backend(db['ENGINE']) conn = backend.DatabaseWrapper(db, alias) setattr(self._connections, alias, conn) return conn django.db.utils