2008年5月13日火曜日

Calendar

calendar あるいは dateutil http://labix.org/python-dateutil
もあるけれども、 range を使うのがわかりやすいか。



y1 = 2007
y2 = 2008
yy = range(y1,y2) # (2001,2002 ..2008)
mm = range(1,13) # (1,2 ... 12 )
print yy, mm

for y in yy:
for m in mm:
m = str(m)
if len(m) == 1:
m = '0' + m
ym = str(y) + '-' + str(m)
print ym # 2008-01,2008-02

import datetime

today = date.today()
print today # 2008-05-13

t = datetime.timedelta(weeks=2)
print t

import calendar
print calendar.setfirstweekday(calendar.SUNDAY)
print calendar.calendar(2008)

[2007] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
2007-01
2007-02
2007-03
2007-04
2007-05
2007-06
2007-07
2007-08
2007-09
2007-10
2007-11
2007-12
2008-05-13
14 days, 0:00:00
None
2008

January February March
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1
6 7 8 9 10 11 12 3 4 5 6 7 8 9 2 3 4 5 6 7 8
13 14 15 16 17 18 19 10 11 12 13 14 15 16 9 10 11 12 13 14 15
20 21 22 23 24 25 26 17 18 19 20 21 22 23 16 17 18 19 20 21 22
27 28 29 30 31 24 25 26 27 28 29 23 24 25 26 27 28 29
30 31

April May June
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 3 1 2 3 4 5 6 7
6 7 8 9 10 11 12 4 5 6 7 8 9 10 8 9 10 11 12 13 14
13 14 15 16 17 18 19 11 12 13 14 15 16 17 15 16 17 18 19 20 21
20 21 22 23 24 25 26 18 19 20 21 22 23 24 22 23 24 25 26 27 28
27 28 29 30 25 26 27 28 29 30 31 29 30

July August September
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 1 2 1 2 3 4 5 6
6 7 8 9 10 11 12 3 4 5 6 7 8 9 7 8 9 10 11 12 13
13 14 15 16 17 18 19 10 11 12 13 14 15 16 14 15 16 17 18 19 20
20 21 22 23 24 25 26 17 18 19 20 21 22 23 21 22 23 24 25 26 27
27 28 29 30 31 24 25 26 27 28 29 30 28 29 30
31

October November December
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 1 1 2 3 4 5 6
5 6 7 8 9 10 11 2 3 4 5 6 7 8 7 8 9 10 11 12 13
12 13 14 15 16 17 18 9 10 11 12 13 14 15 14 15 16 17 18 19 20
19 20 21 22 23 24 25 16 17 18 19 20 21 22 21 22 23 24 25 26 27
26 27 28 29 30 31 23 24 25 26 27 28 29 28 29 30 31
30

2008年5月12日月曜日

urlfetch で rss.xml より img を検出





http://localhost:8080/_ah/admin/interactive より実行


from google.appengine.api import urlfetch
from elementtree.ElementTree import *
import re

rss1 = 'http://movies.go.com/xml/rss/intheaters.xml'
url = rss1
rss = urlfetch.Fetch(url)
print rss
tree = ElementTree(fromstring(rss.content))

img_re = re.compile('<img src="([a-zA-Z0-9/:._\-]+)" ')
for item in tree.findall('.//item'):
title = item.find('title').text.strip()
description = item.find('description').text.strip()
imageMatch = img_re.search(description)
if (imageMatch):
picture_url = imageMatch.groups()[0]
print title
print picture_url

---

Speed Racer
http://movies.go.com/i/movies/895881/895881.jpg



--- 特定のページの src = .jpg 検出 ---

from google.appengine.api import urlfetch
from elementtree.ElementTree import *
import re
url = 'http://webdba.blogspot.com/2008/05/urlfetch-rss-img.html'
content = urlfetch.Fetch(url).content
img_re = re.compile('<img src="([a-zA-Z0-9/:._\-]+)" ',re.I)
img_re = re.compile('src="([a-zA-Z0-9/:._\-]+).jpg" ',re.I)
img_re = re.compile('src="([a-zA-Z0-9/:._\-]+[jpg|gif|png])" ',re.I)

imageMatch = img_re.search(content)
imageMatch = img_re.findall(content)
print imageMatch
for i in imageMatch:
print i

---

['http://code.google.com/appengine/images/appengine_lowres.jpg']
http://code.google.com/appengine/images/appengine_lowres.jpg

2008年5月9日金曜日

正規表現, 文字列の置換



文字列の置換 string.replace()


---
import string
str1 = "http://localhost"
str2 = string.replace(str1, 'http', 'file')
print str1
print str2
---
http://localhost
file://localhost
-----------------------------------

リテラルのバックスラッシュにマッチさせるには、正規表現文字列として
'\\\\'


Python では raw 文字列(raw string)表記を正規表現に利用
先頭に  r  を付加する
p = re.compile(r'([^"])\b((http|https)://[^ \t\n\r<>\(\)&"]+' \
r'[^ \t\n\r<>\(\)&"\.])')


http://www.python.jp/Zope/articles/tips/regex_howto/regex_howto_3
http://reddog.s35.xrea.com/wiki/Python%C8%F7%CB%BA%CF%BF.html Python備忘録


改行文字を取り除くときは、 s[:-1] または s.rstrip('\n')

-------------------------------------------------------------
import re
p = re.compile("ab.", re.I)
result = p.findall("AbdABCAAbb")
print result

p = re.compile("ab.")
print p.sub("xxx", "abcdeaabcde")
print p.sub("xxx", "Abcdeaabcde")

p = re.compile("ab.", re.I)
print p.sub("xxx", "Abcdeaabcde")
print "------------"

url = "aa https://aa.com/ bb"

p = re.compile(r'([^"])\b((http|https)://[^ \t\n\r<>\(\)&"]+' \
r'[^ \t\n\r<>\(\)&"\.])')

m = p.match('aa http://aa.com/ bb' + url + url )
print m
m = p.sub('XXX','aa http://aa.com/ bb' + url + url )
print m
print "------------"

# print m.group(0)

print "-- " + url + " --"
print "->"
print p.sub("xxx", url )

p = re.compile('[a-z]+')
m = p.match('tempo')
print m
print m.group(0)

-----

from google.appengine.api import urlfetch
from elementtree.ElementTree import *
import re

url = 'http://blog.goo.ne.jp/xxxxxx/m/200803'
#content = urlfetch.Fetch(url).content.decode("euc-jp")
content = url.split('/')

print content[0]
print content[1]
print content[2]
print content[3]

content = url.split('/')[2]
print content

google.appengine.api.datastore


cccwiki サンプルではPage オブジェクトを作成している
 
 この内容は Datastore Viewerでも参照することができる。
























 その基本動作の確認

c:/Program Files/Google/google_appengine/google/appengine/api/datastore.py

import os
from google.appengine.api import datastore
from google.appengine.api import datastore_types

name = 'test'
entity = datastore.Entity('Page')
entity['name'] = name

query = datastore.Query('Page')
query['name ='] = name
entities = query.Get(1)
print >> sys.stdout, len(entities)
print >> sys.stdout, entities[0]
print >> sys.stdout, entities[0]['user']
print >> sys.stdout, entities[0].key()
print >> sys.stdout, entities[0].key().id()
------
1
{u'content': u'<h1>test</h1>', u'user': users.User(email='test@example.com'), u'modified': datetime.datetime(2008, 5, 9, 14, 41, 30, 62000), u'name': u'test', u'created': datetime.datetime(2008, 5, 9, 14, 41, 30, 62000)}
test@example.com
agpoZWxsb3dvcmxkcgsLEgRQYWdlGJQBDA
148

DatePropertyにはやはり不具合(bug)あり



date = db.DateTimeProperty(auto_now_add=True) の値が
対象の datastore のデータを更新する度に、時刻が進んでいってしまう現象は
以下の Patch により直った。 ( SDK 1.0.1)

DateProperty does not work properly in dev environment
http://code.google.com/p/googleappengine/issues/detail?id=131

c:/Program Files/Google/google_appengine/google/appengine/api/datastore_types.py

I tried a patch to module datastore_types.py, which seems to work:

change line 1033
from
lambda val: datetime.datetime.fromtimestamp(float(val) / 1000000.0),
to
lambda val: datetime.datetime.utcfromtimestamp(float(val) / 1000000.0),

Per the Python doc, fromtimestamp() converts to the local timezone.

2008年5月2日金曜日

Key names and IDs cannot be used like property values


   key と key_name と ID があり、これを理解していないいけない。
   
   GQL で key は select できるが、 key_name や ID は select できない。
   ・ select してきた key から key_name や ID を知ることはできる。
            ・ 検索条件に ID や key_name を指定することができる。
            ・ 検索条件に key を指定することは GQL ではできない。

注意: datastore には2つある   
from google.appengine.ext import db       これが GQL  api の解説あり
from google.appengine.api import datastore これは cccwiki のサンプルなどで使用されている


key_name 指定して put すると













ID は空欄で、Key_Name に値が保存される。






import sys #import sys module for printing to stdout
from google.appengine.ext import db

class Car(db.Model):
brand = db.StringProperty(required=True)
wheels = db.ListProperty(db.Key)

mercedes = Car(brand="Mercedes", key_name ="b")
# mercedes.put()
print >> sys.stdout, mercedes.brand

select = mercedes.get_by_id( 130 )
print >> sys.stdout, select.brand

select = mercedes.get_by_key_name( "b" )
print >> sys.stdout, select.brand

id = 130
select = Car.get(db.Key.from_path('Car', id))
print >> sys.stdout, select.brand

key_name = "b"
select = Car.get(db.Key.from_path('Car', key_name))
print >> sys.stdout, select.brand

print >> sys.stdout, select.key()
print >> sys.stdout, select.key().id()
print >> sys.stdout, select.key().name()



select * from Greeting where key = "xxxx"
select * from Greeting where id = xxx
のような検索はできない。

select user_name from Greeting where id = xxxx
update Greeting set user_name = 'new name' where id = xxxx
のかわりに
greetings = db.GqlQuery("SELECT * FROM Greeting")

id = greeting.key().id()

id = int(self.request.get('id'))
greeting = Greeting.get(db.Key.from_path('Greeting', id))

row id から再度検索する必要なない。
get(db.Key.from_path('Greeting', id) これが再検索と同じ

key さえわかれれば db.get() で OK
from google.appengine.ext import db
r = db.get("agpoZWxsb3dvcmxkcgsLEgRCbG9nGNQBDA")
print r.title



Tip: Key names and IDs cannot be used like property values in queries. However, you can use a named key, then store the name as a property. You could do something similar with numeric IDs by storing the object to assign the ID, getting the ID value using obj.key().id(), setting the property with the ID, then storing the object again.

http://code.google.com/appengine/docs/datastore/keysandentitygroups.html#Kinds_Names_and_IDs

http://code.google.com/appengine/articles/djangoforms.html

追加仕様検討
Issue 178: Add unique=True/False to db.property constructor to ensure uniqueness
http://code.google.com/p/googleappengine/issues/detail?id=178

Trunsaction / run_in_transaction
http://code.google.com/appengine/docs/datastore/functions.html#run_in_transaction

2008年5月1日木曜日

Google App Engine / ワイルドカード検索



 部分一致検索はできないようだが、擬似的に行うことができる。
ただ、これも unicode がからむと少々注意が必要

下記を参考に helloworld.py にてテストしたが、
 #!-*- coding:utf-8 -*- がきいているためか、

 OK
greetings = db.GqlQuery("SELECT * FROM Greeting where content >= :1 and content < :2 ",
search_key, search_key + u"\uFFFD" )
 NG
# greetings = db.GqlQuery("SELECT * FROM Greeting where content >= :1 and content < :2 ", # search_key, urllib.unquote(search_key).decode("utf8") + u"\uFFFD" )

でした。 http://code.google.com/appengine/docs/datastore/queriesandindexes.html
Tip: Query filters do not have an explicit way to match just part of a string value, but you can fake a prefix match using inequality filters:

db.GqlQuery("SELECT * FROM MyModel WHERE prop >= :1 AND prop < :2", "abc", "abc" + "\xEF\xBF\xBD")

This matches every MyModel entity with a string property prop that begins with the characters abc. The byte string "\xEF\xBF\xBD" represents the largest possible Unicode character. When the property values are sorted in an index, the values that fall in this range are all of the values that begin with the given prefix.

http://groups.google.com/group/google-appengine/browse_thread/thread/47abf4b8842ab865?hl=en

Next problem is that I can't search the datastore with a parameter
from the query string, something like this:

import urllib

q = "Ambj%C3%B6" # Url encoded u"Ambjö"

fsgs = db.GqlQuery("SELECT * FROM Fsg WHERE fsg >= :1 AND fsg < :2", urllib.unquote(q), urllib.unquote(q) + u'\uFFFD')

Works perfect if I only have ascii characters. Is urllib.unquote wrong
utility for this?

> q = "Ambj%C3%B6" # Url encoded u"Ambjö"
> fsgs = db.GqlQuery("SELECT * FROM Fsg WHERE fsg >= :1 AND fsg < :2", > urllib.unquote(q), urllib.unquote(q) + u'\uFFFD')


You've got a similar problem as before. The string urllib.unquote()
returns isn't a Unicode string either, so you need to convert it to
Unicode. Eg:
urllib.unquote(q).decode("utf8") + u"\uFFFD"

2008年4月29日火曜日

Google App Engine / 管理コンソール



Docs > The Dev Web Server
以下の URL で開発環境の Development Console にアクセスし、datastore の内容を確認することができる。
http://localhost:8080/_ah/admin

http://localhost:8080/_ah/admin/datastore?kind=Greeting

このプログラムのソース
c:/Program Files/Google/google_appengine/google/appengine/ext/admin/__init__.py

2008年4月26日土曜日

Google App Engine / django template カスタムタグ


  django のテンプレートをカスタマイズすることができた。
  (django template にカスタム filter を追加することができた)




-- templatefilters.py
#!-*- coding:utf-8 -*-

# import the webapp module
from google.appengine.ext import webapp
import datetime


# get registry, we need it to register our filter later.
register = webapp.template.create_template_register()

def truncate(value,maxsize,stopper = '...'):
""" truncates a string to a given maximum
size and appends the stopper if needed """
stoplen = len(stopper)
if len(value) > maxsize and maxsize > stoplen:
return value[:(maxsize-stoplen)] + stopper
else:
return value[:maxsize]

def timeJST (value):
# return value - datetime.timedelta(hours=18)
return value + datetime.timedelta(hours=9)
# SDK102 にしたら動作がかわった???

register.filter(truncate)
register.filter(timeJST)

-- index.html
{{ greeting.date|timeJST|date:"Y/m/d H:i:s" }}

-- helloworld.py
webapp.template.register_template_library( 'templatefilters')

参照元

2008年4月25日金曜日

Google App Engine / flickr API 表示サイズ


http://www.flickr.com/services/api/  で検索結果の画像の表示のサイズの変更について、テストした結果をメモしておく。
テンプレートの変更による。 ( 送信するパラメータは変更なし)
検索キーワードは "Michaelangelo Moses" を設定







/sizes/
_m.jpg




























/sizes/
.jpg

  • 拡張子なし。
  • これが一番大きな検索結果が表示された。




















/sizes/l/
_b.jpg



  • _b.jpg だと一部の画像が表示されない
  • UNAVAILABLE の表示であっても、クリックした先の flickr のサイトの画像は表示される。


















/sizes/sq/
_s.jpg

















/sizes/t/
_t.jpg
















/sizes/o/
_o.jpg



  • UNAVAILABLE の表示
  • クリック : flickr のサイトのオリジナルサイズの画像が表示される。




















2008年4月24日木曜日

Google App Engine / url fetch API



 先日のサンプルプログラムはあきらめ URL Fetch API用の別の以下のプログラム

 のサンプルは動作させることができた。


http://localhost:8080/flickr/

Flickr の API Key も http://www.flickr.com/services/から取得
いろいろな API http://www.flickr.com/services/api/ が用意
されている。

プロジェクトフォルダ以下のファイルリスト
│  app.yaml
│ flickr.html
│ flickr.py
│ index.yaml
│ webSimple.py
│ webSimple.pyc

└─elementtree
ElementInclude.py
ElementPath.py
ElementPath.pyc
ElementTree.py
ElementTree.pyc
HTMLTreeBuilder.py
SgmlopXMLTreeBuilder.py
SimpleXMLTreeBuilder.py
SimpleXMLTreeBuilder.pyc
SimpleXMLWriter.py
TidyHTMLTreeBuilder.py
TidyTools.py
XMLTreeBuilder.py
__init__.py
__init__.pyc

--
SDK102 にしたところ、下記のエラーで動作しなくなる

'photos' : res.parse_xml().find("photos").getchildren(),
AttributeError: 'NoneType' object has no attribute 'getchildren'

2008年4月23日水曜日

Google App Engine Google Data Python Library


Getting Started with the Google Data Python Library

http://code.google.com/support/bin/answer.py?answer=75582

これはきちんと理解しておかないと、いろいろなエラーに時間をとられる。


C:\work\gdata.py-1.0.12.1>c:\python25\python ./setup.py install

-- gdata_test.py を変更

# from xml.etree import ElementTree
from xml.etree import ElementTree, SimpleXMLTreeBuilder
ElementTree.XMLTreeBuilder = SimpleXMLTreeBuilder.TreeBuilder
except ImportError:
# from elementtree import ElementTree
from xml.etree import ElementTre


C:\work\gdata.py-1.0.12.1>c:\python25\python ./tests/run_data_tests.py
Running all tests in module gdata_test...............
----------------------------------------------------------------------
Ran 15 tests in 0.031s
OK


サンプルプログラム muvmuv を下記からダウロ
ードして実行してみたのだが
http://code.google.com/support/bin/answer.py?answer=75582

起動
C:\google>dev_appserver.py muvmuv/
これはOK

実行
http://localhost:8080/build
しかし、これが NG

原因検索
http://groups.google.com/group/google-appengine/browse_thread/thread/b7399a91c9525c97

対策
http://effbot.org/downloads/ からelementtree-1.2.7-20070827-preview.win32.exe [52k]
を入れ、これを直接 project フォルダ以下に置いたが
C:\google\muvmuv\elementtree

結論としては windows SDK の不具合で fix 待ち 
http://code.google.com/p/googleappengine/issues/detail?id=222 this is a current issue with the Windows SDK.


--- その他 作業memo ---

Python版インストール(Windows) を参考に
PYTHONPATH=C:\Python25\Lib\site-packages を一応、設定

C:\google\muvmuv\ElementTree.py in ()
cannot import name SimpleXMLTreeBuilder

エラー例
Then I got "No module named expat: use SimpleXMLTreeBuilder instead".
'SimpleXMLTreeBuilder' is not defined

File "C:\google\muvmuv\main.py", line 235, in getMoviesFromRss
tree = ElementTree(fromstring(rss.content))
NameError: global name 'fromstring' is not define

Traceback (most recent call last):
File "C:\Program Files\Google\google_appengine\google\appengine\ext\webapp\__init__.py", line 484, in __call__
handler.get(*groups)
File "C:\google\muvmuv\main.py", line 215, in get
movies = self.getMoviesFromRss(rss1, build_only)
File "C:\google\muvmuv\main.py", line 235, in getMoviesFromRss
tree = ElementTree(fromstring(rss.content))
File "C:\google\muvmuv\elementtree\ElementTree.py", line 1013, in XML
return api.fromstring(text)
File "C:\google\muvmuv\elementtree\ElementTree.py", line 181, in fromstring
parser = XMLTreeBuilder()
File "C:\google\muvmuv\elementtree\ElementTree.py", line 1171, in __init__
self._parser = parser = expat.ParserCreate(None, "}")
NameError: global name 'expat' is not defined

---
Please see http://code.google.com/p/googleappengine/issues/detail?id=222 this is a current issue with the Windows SDK.

expat.py は pyexpat.py を import
コマンドラインからはエラーは発生しない DLLs/pyexpat.pyd などがある。

C:\google>c:\python25\pythonPython 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] onwin32Type "help", "copyright", "credits" or "license" for more information.
>>> from pyexpat import *


SDK102 にしたら build できた


最初起動時に simplejsonエラーが発生したが
以前どうやら django 以下に試行錯誤で置いた
ファイルをプロジェクトフォルダに copy して対応。


exec module_code in script_module.__dict__ File "C:\google\muvmuv\main.py", line 8, in import simplejson ImportError: No module named simplejson

 画像をクリックすると
 以下のエラーが発生しているが、これは
 対応できそうである。











File "C:\google\muvmuv\main.py", line 43, in get
template_values = {'login': loign, 'logout': logout, 'user': user}
NameError: global name 'loign' is not defined


2008年4月19日土曜日

Google App Engine /GqlQuery object and JSON


how to convert GqlQuery object to JSON format



http://groups.google.com/group/google-appengine/browse_thread/thread/634e7b9a2e584dd3?hl=en

How to use simplejson with GqlQuary object for example how to convert
marker_list to JSON for format
marker_list = db.GqlQuery('SELECT * FROM Marker')

I think you should dump queryset or row to python data, then convert
them to json format, here is my testing code:

def dumprow(r):
import datetime
a = {}
for k in r.fields().keys():
v = getattr(r, k)
a['id'] = r.key().id()
a['key'] = str(r.key())
if isinstance(v, str):
a[k] = str(v)
elif isinstance(v, unicode):
a[k] = unicode(v)
elif isinstance(v, datetime.datetime):
a[k] = v.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(v, datetime.date):
a[k] = v.strftime('%Y-%m-%d')
elif isinstance(v, datetime.time):
a[k] = v.strftime('%H:%M:%S')
elif isinstance(v, (int, float, list)):
a[k] = v
else:
a[k] = str(v)

return a

def dumpquery(query):
s = []
for r in query:
s.append(dumprow(r))
return s

Google App Engine 1.0.1 / sampels



Google App Engine SDK のバージョンが 1.0.1 になっていたので Update。
  http://code.google.com/appengine/downloads.html
 (アプリケーションの削除により、一旦削除してから、再度インストール)

 
また、google-app-engine-samples に登録されているものを、いくつか動かしてみた。
まず、これらのソースをながめてみるのがいいようだ。
http://code.google.com/p/google-app-engine-samples/downloads/list

Google App Engine Helper for Django  というものもある。
http://googleappengine.blogspot.com/2008/04/google-app-engine-helper-for-django.html
http://code.google.com/p/google-app-engine-django/

2008年4月14日月曜日

Google App Engine 入門7 検索まとめ

 

  こでまでの作業のまとめ
 以下が追加事項一覧です。

  1. dataJST を追加し、時刻を加工しJSTの時刻も合わせて登録するようにした。
    (が、時間の足し引きの値の理屈がどもう怪しい)
  2. 検索機能 (JQuery にて同じ画面内に絞り込んだ検索結果を表示)
  3. 該当件数表示
  4. Javascript (JQuery のライブラリ)を利用するようにした。
  5. スタイルシート main.css を多少加工した。
  6. イメージ画像の追加 ( app.yaml をよく理解していないこともあり、苦労した。Configuring an App もみてみたが、やはり実例がわかりやすい)
  • テンプレートを使用しないと datastore からの検索結果と同時に日本語を表示しようとすると UnicodeDecodeエラーが発生することから、これを利用。 やはりテンプレートは楽だと思います。

  • ただし、JQuery で検索結果をダイナミックに表示する部分はテンプレートは使用せずに直接記述しました。

  • テンプレートにタグを追加しようと調べたましたが、簡単ではないので中止。

Google App Engine 入門6 検索件数


Docs > Datastore API > Keys and Entity Groups の
Entity Groups, Ancestors and Paths の以下の部分は重要そうです。


When the application creates an entity, it can assign another entity as the parent of the new entity. Assigning a parent to a new entity puts the new entity in the same entity group as the parent entity.

An entity without a parent is a root entity. An entity that is a parent for another entity can also have a parent. A chain of parent entities from an entity up to the root is the path for the entity, and members of the path are the entity's ancestors. The parent of an entity is defined when the entity is created, and cannot be changed later.


データモデルについてはgoogle-appengine groupも議論が行われている 1:1,1:n 
Small tutorial on ER-modeling with GAE - 6 new
http://groups.google.com/group/google-appengine/t/aa26d529d66ac376?hl=en

  I wrote a small tutorial about ER-modeling with Google App Engine:
  http://daily.profeth.de/2008/04/er-modeling-with-google-app-engine.html


fulltext search機能の現状について  Indexing Large Chunks of Text for Search
 There's no ranking, which is a killer drawback. (致命的欠点)
 no exact phrase match, substring match, boolean operators,
 support for stop words (common words that are not indexed) is currently limited to English.


・検索結果の件数について

Docs > Datastore API > GqlQuery を参考
* bind()
* get()
* fetch()
* count()

greetings = Greeting.all().order('-date')
row_cnt = greetings.count()
で件数をカウントすることができました。

Google App Engine 入門5 検索


Datastore API > Creating, Getting and Deleting Data にQuery と GqlQuery の2通りの例がありますが、今回は Query を利用してみます。


1. 単純動作テスト 検索条件の追加
content の値が 'Foo'  のものだけ表示するようにしてみます。
greetings = Greeting.all().order('-date')
greetings.
filter('content =', 'Foo')       # 追加
これは素直に動作しました。

2.  Key とは ?

rowid にあたるような、ものがあります。
unique key that represents the object.
Doc だと APIs > Datastore API > Reference > Key です。

The key() method で得た値(Key object)を put() in the datastore したりすると NotSavedError エラーになるとあります。 RDBMS の場合の一意制約違反のエラーのようなものだと思います。

instance for a given Key using the get() function.
この部分は実際のデータをみてみないとこの先の機能の意味がつかめそうもありません。
key = greeting.key()
self.response.out.write('%s' % str(key) )
self.response.out.write('%s' % greeting.get(key) )
          このような値が返ってきていました。
agpoZWxsb3dvcmxkcg4LEghHcmVldGluZxgTDA
<__main__.Greeting object at 0x02600B30>
なるほど、key がわかれば、 get(key) でたどって実際の値もわかるということです。

key の理解にはReferenceProperty model とういうのもポイントのようです。
あと、ancestor() methods on the object というのが、まだよく理解できていません。


さて、ようやくある程度、検索が動作すようになったと思っていたら、日本語からみのいやなエラーが発生しだしました。

body 内に日本語を使用する self.response.out.write("日本語") だけでエラーとなります。 
INFO 2008-04-16 16:24:10,546 dev_appserver.py] "GET / HTTP/1.1" 500 -
Traceback (most recent call last):
File "C:\Python25\lib\wsgiref\handlers.py", line 92, in run
self.result = application(self.environ, self.start_response)
File "C:\Program Files\Google\google_appengine\google\appengine\ext\webapp\__i
nit__.py", line 504, in __call__
response.wsgi_write(start_response)
File "C:\Program Files\Google\google_appengine\google\appengine\ext\webapp\__i
nit__.py", line 223, in wsgi_write
body = self.out.getvalue()
File "C:\Python25\lib\StringIO.py", line 270, in getvalue
self.buf += ''.join(self.buflist)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe3 in position 13: ordinal
not in range(128)
発生するようになったタイミングはこの部分の追加以降
greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")
for greeting in greetings:
if greeting.author:
self.response.out.write('wrote:' )
self.response.out.write('%s wrote:' % greeting.author.nickname())
else:
self.response.out.write('An anonymous person wrote:')
self.response.out.write('%s' %
cgi.escape(greeting.content))


困ったものです
self.response.headers['Content-Type'] = 'text/html'
self.response.headers['charset'] = 'UTF-8'
では効果なし。
発生例はかなり報告されていますが・・・

いろいろ試してもうまくいきませんが、テンプレートを利用した場合はこうした日本語の問題は発生しないようですので、やはりテンプレート利用する方向になりそうです。

Google App Engine 入門4 Pythonで時差の処理




テンプレートの利用はあきらめて、Python 本体にて時刻の計算処理を行うことにしました。 (index.html でなく helloworld.py を変更)

Types and Property ClassesDatastore Value Types datetime.datetime に説明があります、
さらに詳細は Python へ  the datetime module documentation. のリンクとなています。
日本語だとこのあたりが timedeltaオブジェトなのですが、Python 自体に慣れていないので、実際に動作テストしてみました。

Pythonによるテストのため、まず PATH=C:\Python25  を追加しておきます。
環境変数 TZ による影響があるようです。

C:\google\helloworld>set TZ=
C:\google\helloworld>python
Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)]
>>> import datetime
>>> print datetime.datetime.now()
2008-04-14 13:17:36.953000
>>>

C:\google\helloworld>set TZ=JST
C:\google\helloworld>python
Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)]
>>> import datetime
>>> print datetime.datetime.now()
2008-04-14 04:21:32.015000
>>>
Ctl+Z で終了
-- test scrit tt.py
import datetime

class JST(datetime.tzinfo):
def utcoffset(self, dt):
return datetime.timedelta(hours=9)
def dst(self, dt):
return datetime.timedelta(0)
def tzname(self, dt):
return "JST"

print datetime.datetime.now().isoformat()
print datetime.datetime.now(JST()).isoformat()
実行結果
C:\google\helloworld>python tt.py
2008-04-14T04:28:33.468000
2008-04-14T13:28:33.468000+09:00

まずは、 helloworld.py の class MainPage にて以下のように出力するようにしました。
for greeting in greetings:
・・・
d = greeting.date + datetime.timedelta(hours=9)
self.response.out.write('%s
' % d.strftime("%Y/%m/%d %H:%M:%S") )
として対応することにしました。

参考
Pythonで現在の日付を取得してフォーマットする
http://www.r-stone.net/blogs/satoshi/2008/02/python.html

2008年4月12日土曜日

Google App Engine 入門3



  helloworld のプログラムのソースを読む


APIs

Users API を利用している
 まず、 from google.appengine.api import users してから

     author = db.UserProperty()      author.nickname()

 Instance Methods として ncikname() と email() が用意されている。
 http://code.google.com/appengine/docs/users/userclass.html

Functions として以下がある
  • create_login_url(dest_url)
  • create_logout_url(dest_url)
  • get_current_user()
  • is_current_user_admin()
  http://code.google.com/appengine/docs/users/functions.html

Datastore API

Overview
The App Engine datastore is not a relational database
いわゆる RDBMS ではない。

An entity can be created by calling the constructor of the class,

class Pet(db.Model):
name = db.StringProperty(required=True) 
pet
= Pet(name="Fluffy",
のように Entiy を定義し、値をセットして

then stored by calling the put() method.

pet.Put()
のようにデータベース( datastore ) に保存する。

The datastore API provides two interfaces for queries:
a query object interface, and a SQL-like query language called GQL.
2種類のインターフェイスを用意していて、1つはSQLみたいなものでGQLといいます。

A query returns entities in the form of instances of the model classes that can be modified and put back into the datastore.
検索した値の更新もできます
構造を把握したところで、テンプレートに以下

{{ greeting.datedate:"Y/m/d H:m:s" }}
を追加して、時間を表示するようにしたところ自動的に登録される時間がJST(日本標準時)でなくUTCとなっているのをなんとかしたい。

DateTimeProperty のところのauto_now_add=True
で時刻が自動設定されています。


author = db.UserProperty()
content = db.StringProperty(multiline=True)
date = db.DateTimeProperty(auto_now_add=True)
テンプレートで対応できれば、ベストなのですが
http://www.djangoproject.com/documentation/0.96/templates/#now
時間表示の書式設定ではフォーマットはいろいろ設定できても、計算まではできないようです。
時刻でなく、数値の加減は filter 機能で対応していました。
{{gdateadd:"-2"}}
このような感じでテンプレート側で対応できますが・・・ 日付の場合、どうするかは次回の検討事項とします。


---- memo
「Google App Engine」のメリットとデメリット

2008年4月11日金曜日

Google App Engine 入門2



Docs > Getting Started >


1. Hello, World!
2 Using the webapp Framework
3 Using the Users Service
4 Handling Forms With webapp
 ここまではチュートリアルのコードをそのまま利用できます。
5 Using the Datastore
 ここでは 4 のソースに追加するようになります。
 SQL を発行して、データベースにアクセスしているようですが、特に自分でデータベースを作成したり、テーブルを作成したりする必要なく、ローカルで稼動しました。
 一時ファイルをデータベースとして作成しているようです。

C:\google>dev_appserver.py --clear_datastore helloworld/
INFO 2008-04-11 16:43:28,375 appcfg.py] Checking for updates to the SDK.
INFO 2008-04-11 16:43:28,780 appcfg.py] The SDK is up to date.
INFO 2008-04-11 16:43:28,780 dev_appserver.py] Attempting to remove file at
c:\docume~1\user\locals~1\temp\dev_appserver.datastore
6. Using Templates
 5 のスクリプトを修正
 Django が導入され、SQL がなくなる。テンプレートの詳細は Django のサイトへ。



7. Using Static Files
 不具合注意

 windows 環境では bug 対応が必要
app.yaml と \google\appengine\tools\dev_appserver.py を修正する。
see -> http://d.hatena.ne.jp/Aoba/20080410/1207842114
 上記も含めいろいろやったが
INFO 2008-04-11 16:01:44,328 dev_appserver.py] "GET /stylesheets/main.css HTTP/1.1" 404 -
が止まらず。 

link type="text/css" rel="stylesheet" href="c:/google/helloworld/stylesheets/main.css"
のように絶対パスで書くとエラーは止まるが、cssは適用されていない様子。
dev_appserver.py は修正した状態。
結局、このファイルは元に戻して、 css ファイルは分けるのをやめた。
- index.html 内に当面、記述

<head>
<style type="text/css">
body {
font-family: Verdana, Helvetica, sans-serif;
background-color: #DDDDDD;
}
</style>
</head>

追記:  以下のような対策で利用可能となりました。 app.yaml の変更

- url: /css/(.*\.css)
static_files: css/\1
upload: css/(.*\.css)


やはり javascript などの利用を考えた場合、別ファイルにできないのはつらい。

8. Uploading Your Application
 アカウントが必要


その他のエラー対応

・ helloworld.py の改行が正しくなく、2行が1行になっているときに以下のようなエラーとなります。

Python 2.5.2: C:\Python25\python.exeFri Apr 11 13:01:06 2008
A problem occurred in a Python script. Here is the sequence of function calls leading up to the error, in the order they occurred.
C:\Program Files\Google\google_appengine\google\appengine\tools\dev_appserver.p in _HandleRequest(self=)
2243 infile,
2244 outfile,
2245 base_env_dict=env_dict)
2246 finally:
2247 self.module_manager.UpdateModuleFileModificationTimes()
base_env_dict undefined, env_dict = {'REMOTE_ADDR': '127.0.0.1', 'REQUEST_METHOD': 'GET', 'SERVER_NAME': 'localhost', 'SERVER_PORT': '8080', 'SERVER_PROTOCOL': 'HTTP/1.0', 'SERVER_SOFTWARE': 'Development/1.0'}


・ main.css ファイルの文字コードが sjis になっていた時のエラー

ERROR 2008-04-11 14:59:53,453 __init__.py] Traceback (most recent call last):
File "C:\Program Files\Google\google_appengine\google\appengine\ext\webapp\__init__.py", line 486, in __call__ handler.post(*groups) File "C:\Documents and Settings\kt\My Documents\google\helloworld\helloworld.py", line 39, in post greeting.put() File "C:\Program Files\Google\google_appengine\google\appengine\ext\db\__init__.py", line 602, in put self._save_to_entity() File "C:\Program Files\Google\google_appengine\google\appengine\ext\db\__init__.py", line 621, in _save_to_entity self._store_to_entity(self._entity) File "C:\Program Files\Google\google_appengine\google\appengine\ext\db\__init__.py", line 587, in _store_to_entity entity[prop.name] = datastore_value File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore.py", line 341, in __setitem__ datastore_types.ToPropertyPb(name, value) File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore_types.py", line 976, in ToPropertyPb pbvalue.mutable_uservalue().set_email(v.email().encode('utf-8'))UnicodeDecodeError: 'ascii' codec can't decode byte 0x82 in position 3: ordinalnot in range(128)
----------------------------------------------------



Google App Engine 入門1



「Google App Engine」の登場とPaaS--Web 2.5がもたらす変化 2008/04/10 17:27
http://japan.cnet.com/column/pers/story/0,2000055923,20371171,00.htm


1. Google App Engine SDK は Python 2.5 が前提
Python 2.5 をインストール         http://www.python.org/download/

2. SDK をインストール
Google App Engine General Questions http://code.google.com/appengine/kb/general.html
Download the SDK をダウンロード    http://code.google.com/appengine/downloads.html


既にパスは通っている。
C:\>path
PATH=C:\WINDOWS\system32;
C:\Program Files\Google\google_appengine\


3. helloworld を動かす

Docs >Getting Started >Hello, World!
を参考に





3.1  2つのファイルを作成

 C:> cd Documents and Settings\user\My Documents\google
 C:> md helloworld

helloworld ディレクトリに以下の2つのファイルを作成

-helloworld.py-

#!-*- coding:utf-8 -*-
print 'Content-Type: text/plain'
print ''
print 'Hello, world!'


* ローカルでなく、 Google Upload の場合、日本語対応には必要
  [ #!-*- coding:utf-8 -*- ] c.f

-app.yaml -
application: helloworld
version: 1
runtime: pythonapi_version: 1
handlers:- url: /.*
script: helloworld.py

5.  DOS prompt より以下のコマンドを実行 (自動的に webサーバーが起動される)
C:\Documents and Settings\user\My Documents\google>dev_appserver.py helloworld/

6.  ブラウザデアクセスしてみる










7.  DOS prompt の出力の様子

C:\Documents and Settings\user\My Documents\google>dev_appserver.py helloworld/
Allow dev_appserver to check for updates on startup? (Y/n): y
dev_appserver will check for updates on startup. To change this setting, edit C:\Documents and Settings\user/.appcfg_nag

INFO 2008-04-11 11:28:02,328 appcfg.py] Checking for updates to the SDK.
INFO 2008-04-11 11:28:02,733 appcfg.py] The SDK is up to date.
WARNING 2008-04-11 11:28:02,733 datastore_file_stub.py] Could not read datastore data from c:\docume~1\user\locals~1\temp\dev_appserver.datastore
WARNING 2008-04-11 11:28:02,733 datastore_file_stub.py] Could not read datastore data from c:\docume~1\user\locals~1\temp\dev_appserver.datastore.history
INFO 2008-04-11 11:28:02,750 dev_appserver_main.py] Running application helloworld on port 8080:
http://localhost:8080

INFO 2008-04-11 11:31:28,092 dev_appserver.py] "GET / HTTP/1.1" 200 -
INFO 2008-04-11 11:31:28,108 dev_appserver_index.py] Updating C:\Documents and Settings\user\My Documents\google\helloworld\index.yaml
INFO 2008-04-11 11:31:28,171 dev_appserver.py] "GET /favicon.ico HTTP/1.1" 200 -
INFO 2008-04-11 11:31:41,296 dev_appserver.py] "GET / HTTP/1.1" 200 -
INFO 2008-04-11 11:31:42,217 dev_appserver.py] "GET / HTTP/1.1" 200 -
INFO 2008-04-11 11:31:45,296 dev_appserver.py] "GET / HTTP/1.1" 200 -



拡張子 .py が Python と関連付けられている。
以前、install した python22 を uninstall した
際、この情報も削除され
c:> dev_appserver.py が起動しなくなった。

Python.exe に PATH が通っている必要はないが
拡張子 .py との関連付けは必要。










8. 紹介 Vide の様子  ひと昔まえまではこうした雰囲気を味わうには会場のいくしかなかった。

http://code.google.com/appengine/

Announcing Google App Engine at Campfire One on April 7, 2008

Unityでドアの開閉はAnimatorそれともiTween?

Mac Mini M2 の Unity で Sketchup のデータを復元したつづき。 以前、苦労して作成したドアの開閉が動作しないので修復する。 どうやって動かしていたのか、また忘れそうなので記録しておく。             Animator 左右のドア PlaneL,...