Archive@2007/11

DjangoでPUTやDELETEやってみたメモ

Django でリクエストをPUTとかDELETEで投げる時に、 ちょろっとハマったのでメモ。

jQueryFlash からPUTやDELETEでリクエストすると、 メソッド自体はちゃんと解釈されるものの、 なぜか渡したデータが取れなかった。 Pylons ではハマらなかったのになぁ。

で、そもそもデータが渡されてるのかを確かめるために、 Requestのraw_post_dataをプリントしてみると、 そこにはちゃんと入ってた。 データの受け渡し自体はちゃんと出来てるらしい。

じゃあ、次はどこでパースしてるか?って事で、 django.core.handlers.wsgi.py を追いかけてみる。

どうやら111行目あたり、 WSGIRequest のメソッドの _load_post_and_files がパースしてるみたいなのですが、 ここで原因を発見。

def _load_post_and_files(self):
    # Populates self._post and self._files
    if self.method == 'POST':   #<-- ココ
        if self.environ.get('CONTENT_TYPE', '').startswith('multipart'):
            header_dict = dict([(k, v) for k, v in self.environ.items() if k.startswith('HTTP_')])
            header_dict['Content-Type'] = self.environ.get('CONTENT_TYPE', '')
            self._post, self._files = http.parse_file_upload(header_dict, self.raw_post_data)
        else:
            self._post, self._files = http.QueryDict(self.raw_post_data, encoding=self._encoding), datastructures.MultiValueDict()
    else:
        self._post, self._files = http.QueryDict('', encoding=self._encoding), datastructures.MultiValueDict()

どうやらPOSTじゃないとリクエストされたデータをパースしないらしいよ。困った。

django.core.handlers.modpython.py も見てみると、 こちらはContent-Typeのみを見て判別してるみたい。

とりあえず、POSTしか受け付けないのはツライので、 PUTとDELETEも追加して対処する事に。

Index: django/core/handlers/wsgi.py
===================================================================
--- django/core/handlers/wsgi.py        (revision 6708)
+++ django/core/handlers/wsgi.py        (working copy)
@@ -110,7 +110,7 @@

     def _load_post_and_files(self):
         # Populates self._post and self._files
-        if self.method == 'POST':
+        if self.method in ('POST', 'PUT', 'DELETE'):
             if self.environ.get('CONTENT_TYPE', '').startswith('multipart'):
                 header_dict = dict([(k, v) for k, v in self.environ.items() if k.startswith('HTTP_')])
                 header_dict['Content-Type'] = self.environ.get('CONTENT_TYPE', '')

とりあえず、コレでPUTやDELETEのデータもちゃんと受け取れるようになったよ。 果たして良いのかどうかは分からんですけども。

これでしばらく様子を見てみよう。

Posted at: 
2007/11/26 23:17:49
2 Comments
1 TrackBack
Tags: 
Django
Python
REST
Trackback: 
http://humming.via-kitchen.com/2007/11/26/tried-put-and-delete-on-django/trackback/

Vimpi launched!!

yoshuki さんが作ったサービスの Vimpi がスタートしたよ!

自分が使ってる vim のプラグインとか登録しておけば、 Feedで更新が分かるっす。 他の人が使ってる .vimrc とかプラグインも見れたりするので、 参考にするってのも出来ちゃうよ。

vimmer な人は是非ともお試しあれ :-)

Posted at: 
2007/11/21 02:32:44
2 Comments
0 TrackBacks
Tags: 
vim
Trackback: 
http://humming.via-kitchen.com/2007/11/21/vimpi-launched/trackback/

焼き肉食べてきたよ。

本日は久しぶりに焼き肉を啄んで参りました。

perezvon さん、 Voluntas さん、 グニャラ さん、 itsukoさん、そして僕というメンツ。 MiCHiLU さんは用事が重なってしまい今回は不参加。むー、残念 :-(

普段聞く事が出来ない話とかも、色々聞けてめちゃめちゃ面白かったよ! やっぱり良いっすね。こういうの。 つながりは大切って、改めて思ったっす。

以下ネタ的に。

  • perezvon さん、 グニャラ さんはものっ凄いデキる方向。(ガロン単位)
  • itsukoさんはHHKの影を感じさせない、とても感じの良い方でした。
  • Voluntas さんは寝袋必須。(じゃんけん大会)
  • デフォルト・バッファ・キュー・スタックは日本語にはなれない。

次回の予定もあるみたいなので、また是非是非参加したいと思っております :-)

Posted at: 
2007/11/21 00:48:01
0 Comments
0 TrackBacks
Tags: 
memo
Trackback: 
http://humming.via-kitchen.com/2007/11/21/ate-broiled-meat/trackback/

JavaScript-XPathを触ってみたよ。

個人的に XPath がトレンドってのもあって、 JavaScript-XPath を使ってみたよ。

amachang さんの こちらのエントリーjQuery のバインディングが公開された事を知って、 XPath for jQuery も使ってちょくちょく触ってみたけど、 全く意識する事無く使えて物凄くいい感じ。

ダウンロードはココからしてきたっす。

JavaScript-XPath
JavaScript-XPath - CodeRepos::Share - Trac
XPath for jQuery
JavaScript-XPath/bindings/jQuery - CodeRepos::Share - Trac

まだまだ大した XPath を書けないので、 キョーレツなテストとかは出来ないけど、 個人的には end() が併用出来るのがめちゃくちゃ嬉しい。 end() って jQuery の重要な機能の1つなので、 これが併用出来るかどうか?でかなり印象が変わってくる(と思う)。

これから常用プラグインとして使っていきそうな勢いなので、 気付いた事とかフィードバックしていけたら良いなぁ。 まずは lxmlJavaScript-XPathXPath と仲良くならなくちゃね。

Posted at: 
2007/11/20 01:53:56
0 Comments
0 TrackBacks
Tags: 
JavaScript
jQuery
XPath
Trackback: 
http://humming.via-kitchen.com/2007/11/20/tried-using-javascript-xpath/trackback/

詳解 MySQLが出てたよ。

今日は本屋に行こうと渋谷まで。 目的の本は ActionScript 3.0 アニメーション 。 まぁ、案の定売り切れらしく置いてなかったよ。 前に立ち読みした感じだと、かなり良さそうだったし、 予想してたから凹みはしなかったけど残念。

やる事も尽きたし、帰ろうかと思った矢先に 詳解 MySQL を発見。もう発売されてたんだ。 ちょっとチラ見してみたら、難しそうだけど面白そう。 Understanding MySQL Internals の和訳らしく、 mir the archive と合わせて読むと良いかも知れない。 給料入ったら購入衝動との戦いになりそう。

Cocoa とか Objective-C の本も良いのがあれば欲しいと思ったけども、 渋谷のBook 1stが移転してて、目当ての本がどこにあるのか検討がつかず撃沈。 オススメがあれば教えてくださいまし。

Posted at: 
2007/11/18 23:14:07
3 Comments
0 TrackBacks
Tags: 
book
memo
Trackback: 
http://humming.via-kitchen.com/2007/11/18/mysql-internals-released/trackback/

lxmlを試してみたよ。(その2)

前回 に続いて lxml を使って色々やってみたよ。

テスト用のファイルを書くのもメンドクサイので、 このサイトのカテゴリーリストで遊んでみる事にした。

>>> from httplib import HTTPConnection
>>> from lxml import etree

>>> #   とりあえずHTMLを取ってくる。
>>> conn = HTTPConnection('humming.via-kitchen.com')
>>> conn.request('GET', '/')

>>> #   レスポンスをパース。
>>> html = etree.parse(conn.getresponse(), parser=etree.HTMLParser()).getroot()

ここから lxml でサクサク遊んでみる。

>>> #   カテゴリーリストを取ってくる。
>>> html.xpath('//div[@id="subContent"]/ul[@class="cloudList"]')
[<Element ul at 2489f90>]
>>> ul = html.xpath('//div[@id="subContent"]/ul[@class="cloudList"]')[0]

>>> #   リストのリンクを取ってくる。
>>> ul.xpath('./li/a')
[<Element a at 2489fc0>, <Element a at 248f720>, ..., <Element a at 248fe70>]

>>> #   リンクのテキストを取ってくる。
>>> ul.xpath('./li/a/text()')
['ActionScript', 'AIR', ..., 'vim']

テキストを取りたい場合は text() 、 ならアトリビュートはどうやって取るんだろう?と疑問が。

で、色々調べたり試したりした結果、 @ATTRIBUTE で取れるらしいっす。

>>> #   hrefを取ってくる。
>>> ul.xpath('./li/a/@href')
['/weblog/tag/actionscript/', '/weblog/tag/air/', ..., '/weblog/tag/vim/']

>>> #   classを取ってくる。
>>> ul.xpath('./li/a/@class')
['rank9', 'rank2', ..., 'rank2', 'rank8']

これが分かると一気に使い勝手が良くなってきた! もうね、 lxml 素敵。ってか XPath 素敵。

Posted at: 
2007/11/14 03:00:24
0 Comments
0 TrackBacks
Tags: 
lxml
Python
XPath
Trackback: 
http://humming.via-kitchen.com/2007/11/14/tried-using-lxml-part2/trackback/

lxmlを試してみたよ。

遅ればせながら lxml を試してみたよ。コレ、かなり便利っすなぁ。

インストールは easy_install でするのが簡単で良いと思う。 yolk で検索してみると、2.0alphaとかも出てきたので、 今回はバージョンを指定してインストールしてみた。

$ sudo easy_install lxml==1.3.6

テスト用にこんな感じのXMLを用意して、 test.xml とかで保存。

<?xml version="1.0" encoding="UTF-8"?>
<items>
    <item>
        <id>1</id>
        <name>hoge</name>
        <type>word</type>
    </item>
    <item>
        <id>2</id>
        <name>hige</name>
        <type>word</type>
    </item>
    <item>
        <id>3</id>
        <name>hage</name>
        <type>image</type>
    </item>
</items>

lxml を使って遊んでみる。

>>> from lxml import etree
>>> xml = etree.parse(open('test.xml', 'r'), parser=etree.XMLParser())
>>> xml
<etree._ElementTree object at 0x7406c0>

>>> #   ルートノード(items)を取ってくる。
>>> items = xml.getroot()
>>> items
<Element items at 7417b0>

>>> #   子要素(item)を取ってくる。
>>> items.getchildren()
[<Element item at 7417e0>, <Element item at 7418a0>, <Element item at 741840>]

>>> #   XPathで子要素(item)を取ってくる。
>>> items.xpath('./item')
[<Element item at 7417e0>, <Element item at 7418a0>, <Element item at 741840>]

>>> #   XPathで孫要素(name)のテキストを取ってくる。
>>> items.xpath('./item/name/text()')
['hoge', 'hige', 'hage']

文字列から直接パースする場合は、 etree.fromstring なメソッドを使うと良いらしい。

>>> text = open('test.xml', 'r').read()
>>> items = etree.fromstring(text, parser=etree.XMLParser())
>>> items
<Element items at 7418a0>

文字列からのパースだと、 getroot しなくても直接ルートノードが返ってくる。

逆に、ノードを文字列にしたい場合だと、 etree.tostring なメソッドを使うと良いみたい。

>>> #   itemノードの1個目を文字列に。
>>> etree.tostring(items.xpath('./item')[0])
<item>
    <id>1</id>
    <name>hoge</name>
    <type>word</type>
</item>

>>> #   最後のitemノードに含まれるnameノードを文字列に。
>>> etree.tostring(items.xpath('./item[position()=last()]/name')[0])
<name>hage</name>

色々簡単に使えていい感じ。 XPath もちゃんと覚えないとなぁ。 HTMLを扱うときは、 parseretree.HTMLParser にしてあげれば良いよ。

Posted at: 
2007/11/11 19:48:07
2 Comments
1 TrackBack
Tags: 
lxml
Python
XPath
Trackback: 
http://humming.via-kitchen.com/2007/11/11/tried-using-lxml/trackback/

DjangoとMySQLでForeignKeyのつく条件(の続き)

結構前に、 ここらへんDjangoMySQL で動かす場合の、 ForeignKey のつく条件についてやきもきしてた訳ですが、 チケット #5729 で上がってたみたいで、 r6650 で進展があったっぽいよ。

試しに r6649r6650 を比べてみる。 models.py は前回と同じようにしてテストする。

from django.db import models

class Oya(models.Model):
    body = models.TextField()

class Kodomo(models.Model):
    parent = models.ForeignKey(Oya)
    body = models.TextField()

これで、 r6649sql を叩くとこんな感じ。

BEGIN;
CREATE TABLE `hige_oya` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `body` longtext NOT NULL
)
;
CREATE TABLE `hige_kodomo` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `parent_id` integer NOT NULL REFERENCES `hige_oya` (`id`),
    `body` longtext NOT NULL
)
;

これが r6650 だとこう変わる。

BEGIN;
CREATE TABLE `hige_oya` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `body` longtext NOT NULL
)
;
CREATE TABLE `hige_kodomo` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `parent_id` integer NOT NULL,
    `body` longtext NOT NULL
)
;
-- The following references should be added but depend on non-existent tables:
-- ALTER TABLE `hige_kodomo` ADD CONSTRAINT parent_id_refs_id_66492efa FOREIGN KEY (`parent_id`) REFERENCES `hige_oya` (`id`);
COMMIT;

変わった事は変わったんだけど、なぜコメントアウト? 「存在しないテーブルへの参照だから。」って言われても、ちゃんとあるんだけどなぁ。

実際作られるテーブルを見てみると、両方とも前回同様こうなった。

mysql> SHOW CREATE TABLE `hige_kodomo`\G
*************************** 1. row ***************************
       Table: hige_kodomo
Create Table: CREATE TABLE `hige_kodomo` (
  `id` int(11) NOT NULL auto_increment,
  `parent_id` int(11) NOT NULL,
  `body` longtext NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `hige_kodomo_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

#5729 は既にクローズされてるし、実に悩ましい。 って言うより、こういう時にリオープン出来るだけの英語力がない(実力もない)のが何よりも悩ましい。

Posted at: 
2007/11/05 22:41:49
0 Comments
1 TrackBack
Tags: 
Django
MySQL
Python
Trackback: 
http://humming.via-kitchen.com/2007/11/05/mysql-foreignkey-on-django/trackback/

Safariで検索フォームをちょっと素敵に。

Safari でちょっとした小ネタを発見。

HTMLのinputで、typeを search にすると、 角丸のいい感じのテキストエリアに変身してくれるっす。

さらに resultsautosave を追加すると、 履歴をちゃんと保持してくれるようになる。 results で履歴を保持する数を指定し、 autosave で保存するユニークなID?を指定するみたい。 実際にドコに保存されるかまでは未調査っす。

こんな感じに書くと、

<input type="search"
       results="10"
       autosave="example.com">

こんな感じになるよ。

search_input

Safari (ってか Webkit ?)でしか意味ないけど、 こういうのちょっと素敵。 Firebugで見てもエラー吐かなかったので、 とりあえず良し。

Posted at: 
2007/11/04 23:55:38
0 Comments
0 TrackBacks
Tags: 
design
Safari
Trackback: 
http://humming.via-kitchen.com/2007/11/04/tips-for-search-form-on-safari/trackback/

Djangoのエラーメッセージがugettext_lazyに。

ちょっと前から Django のtrunkを使うようになっているのですが、 r6520 から r6635 にアップデートしたらログイン部分がエラー吐いて動かなくなった。

ちょっと調べてみると、 r6625newforms のエラーメッセージが ugettext から ugettext_lazy に変更されてる。 これが simplejson がシリアライズ出来なくてエラーになっているみたい。

今まであんまり意識した事がなかったので、ちょっとだけ実験してみた。

>>> from django.utils.translation import ugettext, ugettext_lazy
>>> s = u'This field is required.'

>>> # ugettextだとこうなる。
>>> ugettext(s)
u'This field is required.'
>>> print ugettext(s)
This field is required.

>>> # ugettext_lazyだとこうなる。
>>> ugettext_lazy(s)
<django.utils.functional.__proxy__ object at 0x24a0270>
>>> print ugettext_lazy(s)
<django.utils.functional.__proxy__ object at 0x24a2330>

どうやら ugettext_lazy を使うと、 __proxy__ ってオブジェクトが返ってくるらしい。 こいつを simplejson がシリアライズ出来なくてエラーになってた。

ココでもうちょっと実験してみる。

>>> lazy = ugettext_lazy(s)

>>> # unicodeしてみる。
>>> unicode(lazy)
u'This field is required.'
>>> print unicode(lazy)
This field is required.

>>> # encodeメソッドを呼んでみる。
>>> lazy.encode('utf-8')
>>> 'This field is required.'
>>> print lazy.encode('utf-8')
This field is required.

>>> # force_unicodeしてみる。
>>> from django.utils.encoding import force_unicode
>>> force_unicode(lazy)
u'This field is required.'
>>> print force_unicode(lazy)
This field is required.

どうやら明示的に変換してやる必要があるみたい。 遅延評価の流れってのを少し理解出来たような気がする。

どうやるのが正しいのか?ってのをまだちゃんと理解出来てないので、 とりあえず force_unicode を使ってエラーを回避。

そのうちソースも追いかけてみよう。

Posted at: 
2007/11/02 01:43:11
0 Comments
0 TrackBacks
Tags: 
Django
Python
Trackback: 
http://humming.via-kitchen.com/2007/11/02/change-errormessage-to-ugettextlazy-on-django/trackback/

Categories

Archives