2008-07-27

GQLでReference型の列でIN条件を利用する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
GQLでReference型の列に対してINを利用するのにちょっと悩んでしまったので、メモです。
以下のようなモデルがある時の場合です。

class AAA(db.Model):
name = db.StringProperty(required=True)

class BBB(db.Model):
memo = db.StringProperty(required=True)
ref = db.ReferenceProperty(AAA)

AAAからデータを一回引っこ抜いて、そこでBBB用検索用のIN条件を作成する場合ですが、以下のようにする必要があります。

aaa = db.GqlQuery("SELECT * FROM AAA")
search_list = []
for aa in aaa:
search_list.append(aa.key())
bbb = db.GqlQuery("SELECT * FROM BBB WHERE ref IN :list",list = search_list)

search_list.append(aaa.key())
の部分を
search_list.append(aaa)
としていたら、以下のようなエラーが出てしまったのです。

Traceback (most recent call last):
....
File "C:\...\google\appengine\ext\db\__init__.py", line 1257, in __iter__
return self.run()
File "C:\...\google\appengine\ext\db\__init__.py", line 1589, in run
query_run = self._proto_query.Run(*self._args, **self._kwds)
File "C:\...\google\appengine\ext\gql\__init__.py", line 563, in Run
bind_results = self.Bind(args, keyword_args)
File "C:\...\google\appengine\ext\gql\__init__.py", line 254, in Bind
query.update(enumerated_query)
File "C:\...\google\appengine\api\datastore.py", line 1035, in update
self.__setitem__(filter, value)
File "C:\...\google\appengine\api\datastore.py", line 978, in __setitem__
datastore_types.ToPropertyPb(' ', value)
File "C:\...\google\appengine\api\datastore_types.py", line 958, in ToPropertyPb
'Unsupported type for property %s: %s' % (name, proptype))
BadValueError: Unsupported type for property :


あと、Google App Engineのバグなのかどうかわかりませんが、GQLでINを使ったクエリーの結果に対して、count()を利用するとエラーが出るようです。
これは、ReferencePropertyと関係なくでるようです。StringPropertyでも出ることを確認しました。
ちなみに以下のようなエラーメッセージが出ます。

Traceback (most recent call last):
File "C:\...\google\appengine\ext\webapp\__init__.py", line 499, in __call__
handler.get(*groups)
File "C:\...\myapp.py", line X, in get
xxx = items.count()
File "C:\...\google\appengine\ext\db\__init__.py", line 1286, in count
return self._get_query().Count(limit=limit)
File "C:\...\google\appengine\api\datastore.py", line 957, in Count
self._ToPb(limit=limit), resp)
File "C:\...\google\appengine\api\datastore.py", line 1110, in _ToPb
pb.set_kind(self.__kind.encode('utf-8'))
AttributeError: 'NoneType' object has no attribute 'encode'

最初、ずっとcountしていて何をしてもエラーが出るから原因がなかなかつかめませんでした。

Google App EngineのModelの制限

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Google App EngineでModelを定義するときに、同じモデルに対するReferenceProperty
を二つ設定できない模様(同じモデルに限らないのかもしれないのですが・・・)。

具体的には、

class Users(db.Model):
name = db.StringProperty(required=True)

class Friends(db.Model):
owner = db.ReferenceProperty(Users)
friend = db.ReferenceProperty(Users)

っていうのは、エラーになってしまいました。
しょうがないので、以下のように片方をStringPropertyにしてkey値を文字列に変換して入れて対処してみました。

class Friends(db.Model):
owner = db.StringProperty()
friend = db.ReferenceProperty(Users)

2008-07-08

GQLの制限メモ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
なにかと便利なGoogle App Engineですが、GQLはなれないといけない感じです。
ちょっと試してGQLの制限をメモ
・ORは使えない
・INの使いっぷりはSQLのつもりで書いてはいけない
 以下のような感じで使う

list = ['a1','a2','a3']
ret = db.GqlQuery("SELECT * FROM aaa WHERE col1 IN :1",list)

2008-07-06

pythonで携帯IP制限

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
携帯専用ページにするには、各携帯キャリアのIPアドレスを利用して制限をかけるみたいです。
通常は、htaccessとかでwebブラウザにこのお仕事を任せるのが通常のやり方のようなのですが、pythonのプログラム側で実装してみたいなぁと思ったので試してみました。

まずは、各携帯キャリアの利用IPアドレスが必要なわけですが、それは
http://d.hatena.ne.jp/tomisima/20070903/1188836400
を利用することで取得することができます。
これで取得した結果を適当にファイルなどに保存したりして利用します。

あんまりpython詳しくないのでいまいちな書き方の可能性が高いけど、私はこんな感じでやってみました。
各キャリアのサブネットは24より小さいことはありえないだろうという勝手な思い込みが前提です。


from mobilejp import MobileJP

m = MobileJP()
ret = m.get_cidr()

iplist = []
for carrier in ret :
for cidr in ret[carrier] :
parts = cidr.split("/")
quads = parts[0].split(".")
quads.append(parts[1])
iplist.append(quads)

chkip = os.getenv('REMOTE_ADDR')

q = chkip.split(".")
find = False
for cidr in iplist :
if int(cidr[0]) != int(q[0]) :
continue;
if int(cidr[1]) != int(q[1]) :
continue;
if int(cidr[2]) != int(q[2]) :
continue;
chk4 = int(q[3])
chk4 = chk4 >> (32 - int(cidr[4]))
chk4 = chk4 << (32 - int(cidr[4]))
if int(cidr[3]) == chk4 :
print "OK"
find = True
break;
if find == False :
print "NO"


こんな感じでできていそうな気がします。

2008-07-01

Amazonの個別商品ページを携帯で見る

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
AmazonのWEBサービスを利用することでアフィリエイトつきの商品個別のページのURLを取得することができますが、携帯でこのURLを見ようとするとどうも長すぎて見れないようです。
なので携帯で見るには、別のURLを個別に生成する必要があるようです。

以下が参考になります。
http://tech.bayashi.jp/archives/entry/techweb/2006/001376.html
http://aws.typepad.com/aws_jp/2005/07/amazon_.html

携帯用には、以下のようなURLでいけるようです。
http://www.amazon.co.jp/gp/aw/rd.html?uid=NULLGWDOCOMO&at=[ASSOCIATE_TAG]&a=[ASIN]&o=Add&dl=1&url=%2Fgp%2Faw%2Fc.html
この[ASIN]の部分をWEBサービスで取得してうめることで携帯で見ることができるようです。

iアプリでxmlを読む

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
iアプリでxmlを読むにはkXML2というのを使うといいらしいです。
その方法は、
http://www.ntts.co.jp/products/mobile/detail/article.html

第6回「ケータイ+RSSでドコデモ最新情報ゲット」
というのを見ればわかります。
iアプリのサイズを小さくするためにkXML2の一部のファイルのみを組み込ませる方法が書いてあって役に立ちます。
他の記事もiアプリ情報としてはとても役に立ちますよ。

そしてXMLを使っていれば当たり前のかもしれませんが、
XMLデータ内に&があるとkXML2が解析に失敗するようです。
なのでXMLデータに&を入れたいときは、データをURLエンコードしておく必要があるようです。