2008年5月29日木曜日
Google App Engine SDK1.1.0
http://code.google.com/p/googleappengine/wiki/SdkReleaseNotes
http://code.google.com/appengine/downloads.html
WARNING 2008-05-29 05:45:27,265 dev_appserver.py]
Could not initialize images API;
you are likely missing the Python "PIL" module. ImportError: No module named PIL
2008年5月28日水曜日
SearchableModel が__searchable_text_indexを生成
We've included a short-term full text search library in the
google.appengine.ext.search module. It's limited, so we don't discuss
it much in the documentation. We expect to provide a more robust, full
featured solution eventually.
http://groups.google.com/group/google-appengine/browse_thread/thread/4b912691a00eea59
Having created a SearchableModel entity, updating it doesn't seem to
update the full text index - Is that expected behaviour?
A little unit test to explain what I mean:
import sys, os, time
sys.path.append('/usr/local/google_appengine')
sys.path.append('/usr/local/google_appengine/lib/yaml/lib')
import unittest
from google.appengine.api import apiproxy_stub_map
from google.appengine.api import datastore_file_stub
from google.appengine.api import mail_stub
from google.appengine.api import urlfetch_stub
from google.appengine.api import user_service_stub
from google.appengine.ext import db, search
APP_ID = u'test'
AUTH_DOMAIN = 'gmail.com'
LOGGED_IN_USER = 't...@example.com'
searchtext = db.TextProperty()
.
.
.
Bulk Loader
http://code.google.com/appengine/articles/bulkload.html
1. c:\google\bulkload フォルダを作成し、ここに以下のファイルを作成。
myloader.py
people.csv
2. c:/Program Files/Google/google_appengine/google/appengine/tools/bulkload_client.py
を c:\google\buloload に copy
3. c:\google> dev_appserver.py books/ 作成済みのプログラムを起動
起動まえに 以下のファイルに /load を追加
--- c:\google\books\app.yaml
- url: /
script: books.py
- url: /load
script: myloader.py
login: admin
実行
C:\google\bulkload>bulkload_client.py --filename people.csv
--kind Person
--url http://localhost:8080/load
3. ImportError: No module named google.appengine.ext.bulkload がでるので
3.1 C:\Program Files\Google\google_appengine\google\appengine\ext\bulkload\constants.py
を c:\google\buloload に copyし
3.2 -- c:\google\buloload\bulkload_client.py を一部改訂 --
try:
from google.appengine.ext.bulkload import constants
except:
import constants
3.3 再度実行したが login error となるので books/app.yaml を修正*1
C:\google\bulkload>bulkload_client.py --filename people.csv
--kind Person
--url http://localhost:8080/load
INFO 2008-05-28 21:37:29,276 bulkload_client.py]
Starting import; maximum 10 entities per post
INFO 2008-05-28 21:37:29,276 bulkload_client.py]
Importing 3 entities in 75 bytes
ERROR 2008-05-28 21:37:29,292 bulkload_client.py]
An error occurred while importing: Received code 302:
Requires login ERROR
2008-05-28 21:37:29,292 bulkload_client.py]
Import failed
Success
C:\google\bulkload>
bulkload_client.py --filename people.csv --kind Person --url http://localhost:8080/load
INFO 2008-05-28 21:37:48,947 bulkload_client.py] Starting import;
maximum 10 entities per post
INFO 2008-05-28 21:37:48,947 bulkload_client.py] Importing 3 entities in 75 bytes
INFO 2008-05-28 21:37:54,119 bulkload_client.py] Import succcessful
---
*1 bulkload.py は http で post しているので 安易に app.yaml の
admin 部分のコメントアウトは危険。
元のアプリケーションに
'login_url': users.CreateLoginURL(self.request.uri),
を追加して、ログインしておく。
2008年5月27日火曜日
注意メモ
\n で split して処理するようなケースは注意
\n に限らず split する際は注意
for u in url.split('\n'):
この Propety のデータが表示されなくなる? 落とし穴がある様子。
どこかがわるいのか、なんらかの不具合のからみか?
回避策:
dev_appserver.py により再起動することで表示されるようになる。
Google にはサーバーの運用の実績はあるけれども、ユーザーの開発をサポートした実績は
まだあまりなく、したがって、こうした環境下でのデータの信頼性についても、実績はまだない。
また Gql の where 句の条件に <,> <=. >= などは one property per query
BadFilterError: BadFilterError:工夫すればなんとかなることだけれども。 あと select max(XX) などというのも、まだ(?)
invalid filter: Only one property per query may have inequality filters
(<=, >=, <, >)..
しか使えないというのも気がつかなかった。
( 同じ Property には複数回つかえる
○ date >:1 and date < :2
× date >:1 and date2 < :2
ないので、最小値、最大値なども求めるのも、自分で処理しなければならない。
このあたりはやはり RDBMS の歴史と実績を感じる。
2008年5月24日土曜日
elementtree.ElementTree
http://python.matrix.jp/modules/ElementTree.html
from google.appengine.api import urlfetch
from elementtree.ElementTree import *
url="http://api.flickr.com/services/rest/"
url += "?method=flickr.photos.search&text=test"
url += "&api_key=XXX"
url += "&per_page=3"
result = urlfetch.fetch(url)
#print result.content
tree = ElementTree(fromstring(result.content))
for item in tree.findall('.//photos'):
print item[0].get('id')
print item[0].get('title')
for d in item:
print d.get('title')
There's no need to install anything, ElementTree is included in
Python 2.5
http://docs.python.org/lib/module-xml.etree.ElementTree.html
flickr.photos.search (Google App Engine)
from google.appengine.api import urlfetch
from xml.dom import minidom
url="http://api.flickr.com/services/rest/?method=flickr.photos.search&text=test&api_key=XXX"
result = urlfetch.fetch(url)
dom = minidom.parseString(result.content)
photos = []
for node in dom.getElementsByTagName('photo'):
photos.append({
'server': node.getAttribute('server'),
'id': node.getAttribute('id'),
'secret': node.getAttribute('secret'),
'owner': node.getAttribute('owner'),
'title': node.getAttribute('title')
})
# print node.getAttribute('id'), \
# node.getAttribute('title')
----------------------------
[ templates]
{% for e in photos %}
<a href="http://www.flickr.com/photos/{{ e.owner }}/{{ e.id }}/sizes/" >
<img src="http://static.flickr.com/{{ e.server }}/{{ e.id }}_{{ e.secret }}_s.jpg"
title="{{ e.title }}" border=0 /></a>
{% endfor %}
getElementsByTagName
<?xml version="1.0" encoding="utf-8" ?> <rsp stat="ok"> <method>flickr.test.echo</method> <name>value</name> <api_key>7c7ac3c40f14a809XXXX</api_key> </rsp> | から valueを取り出す。 |
from google.appengine.api import urlfetch
from xml.dom import minidom
url="http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value&api_key=XXX"
result = urlfetch.fetch(url)
print "---result"
print result
print "---result.content"
print result.content
dom = minidom.parseString(result.content)
r =dom.getElementsByTagName('name')[0].firstChild.data
print "---dom.getElementsByTagName"
print r
<?xml version="1.0" encoding="utf-8" ?> <rsp stat="fail"> <err code="100" msg="Invalid API Key (Key not found)" /> &l | からfail を取り出すにはdom.getElementsByTagName('rsp')[0].getAttribute('stat') |
Google App Engine Interactive Console
urlfetch した結果の result ( object ) を
print result.content
とすると、 返信された xml の内容が確認できます。
from google.appengine.api import urlfetch
from xml.dom import minidom
url="http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value&api_key=XXX"
result = urlfetch.fetch(url)
print "---result"
print result
print "---result.content"
print result.content
dom = minidom.parseString(result.content)
r =dom.getElementsByTagName('name')[0].firstChild.data
print "---dom.getElementsByTagName"
print r
Request
Request Format には3つの書式があり、 REST の場合、URL に記述することだけで
リクエストを送信することができます。
http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value実際には以下のように必ず取得した api_key を追加しないとエラーとなります。
http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value&api_key=XXXX
http://www.flickr.com/services/api/
2008年5月22日木曜日
A working XML parsing example!
SimpleXMLTreeBuilder is no longer supported in the latest SDK. Returns
"object is unsubscriptable" error.
Update: I hope this is still useful for people searching for a working
example!
I can confirm that minidom now works in SDK 1.0.2. As I understand
it, this is because pyexpat is now in the GAE whitelist of C
libraries:
http://code.google.com/appengine/kb/libraries.html
I am using SDK 1.0.2 on Windows XP, therefore for this to work I
needed to patch urlfetch_stub.py because the development server was
discarding my URL parameters.
http://code.google.com/p/googleappengine/issues/detail?id=341
You no longer need to use upload a version of the SimpleXMLTreeBuilder
(although this still works) and the code using minidom now looks like
this:
from google.appengine.api import urlfetch
from xml.dom import minidom
WEATHER_URL = 'http://xml.weather.yahoo.com/forecastrss?p=%s'
WEATHER_NS = 'http://xml.weather.yahoo.com/ns/rss/1.0'
def parse( url ) :
result = urlfetch.fetch(url)
if result.status_code == 200:
return minidom.parseString(result.content)
def weather_for_zip(zip_code):
url = WEATHER_URL % zip_code
dom = parse(url)
forecasts = []
for node in dom.getElementsByTagNameNS(WEATHER_NS, 'forecast'):
forecasts.append({
'date': node.getAttribute('date'),
'low': node.getAttribute('low'),
'high': node.getAttribute('high'),
'condition': node.getAttribute('text')
})
return {
'forecasts': forecasts,
'title': dom.getElementsByTagName('title')[0].firstChild.data
}
print 'Content-Type: text/plain'
print ''
print weather_for_zip('94089')
{'title': u'Yahoo! Weather - Sunnyvale, CA', 'forecasts': [{'date': u'22 May 2008', 'high': u'75', 'low': u'53', 'condition': u'Sunny'}, {'date': u'23 May 2008', 'high': u'73', 'low': u'53', 'condition': u'Partly Cloudy'}]}
http://www.kharakawa.com/kh.log/archives/python/
2008年5月19日月曜日
Broken Datastore
削除できなくなる ( fetch も) できなくなってしまう不具合がある。
http://groups.google.com/group/google-appengine/browse_thread/thread/3c3d2da5f7140b18/e80ac633370859db?hl=en&lnk=gst&q=can%27t+delete#e80ac633370859db
%Y ( 2008 ) を省略した日時データを datetime に登録してしまって、削除もできなくなってしまった。
結局 -cleare_datastore してしまったが...
value = datastore_types.FromPropertyPb(prop)
File "C:\Program Files\Google\google_appengine\google\appengine\api\datastore_types.py", line 1102, in FromPropertyPb
'Error converting pb: %s\nException was: %s' % (pb, msg))
BadValueError: Error converting pb: meaning: 7
name: "entry_date"
value <
int64Value: 0xfff831bf8bc87700
>
multiple: false
Exception was: timestamp out of range for platform time_t
http://code.google.com/appengine/docs/thedevwebserver.html
dev_appserver.py --datastore_path=/tmp/myapp_datastore myapp
Default (Windows XP)
C:\Documents and Settings\XXX\Local Settings\Temp\dev_appserver.datastore
C:\Documents and Settings\XXX\Local Settings\Temp\dev_appserver.datastore.history
2008年5月15日木曜日
Entity Groups, Ancestors and Paths
- Every entity belongs to an entity group, a set of one or more entities that can be manipulated in a single transaction.
- Entity group relationships tell App Engine to store several entities in the same part of the distributed network.
- A transaction sets up datastore operations for an entity group, and all of the operations are applied as a group, or not at all if the transaction fails.
- 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.
Tips for using entity groups:
- Only use entity groups when they are needed for transactions. For other relationships between entities, use ReferenceProperty properties and Key values, which can be used in queries.
グループはトランザクションのため
データの関連づけには ReferenceProperty と Key を使う
- class ReferenceProperty(reference_class=None, verbose_name=None, collection_name=None, ...)
-
A reference to another model instance. For example, a reference may indicate a many-to-one relationship between the model with the property and the model referenced by the property.
reference_class is the model class of the model instance being referenced. If specified, only model instances of the class can be assigned to this property. If None, any model instance can be the value of this property.
collection_name is the name of the property to give to the referenced model class whose value is a Query for all entities that reference the entity. If no collection_name is set, then modelname_set (with the name of the model in lowercase letters and "_set" added) is used.
ReferenceProperty automatically references and dereferences model instances as property values: A model instance can be assigned to a ReferenceProperty directly, and its key will be used. The ReferenceProperty value can be used as if it were a model instance, and the datastore entity will be fetched and the model instance created when it is first used in this way. Untouched reference properties do not query for unneeded data.
class Author(db.Model):
name = db.StringProperty()
class Story(db.Model):
author = db.ReferenceProperty(Author)
story = db.get(story_key)
author_name = story.author.nameAs with a Key value, it is possible for a reference property value to refer to a data entity that does not exist. If a referenced entity is deleted from the datastore, references to the entity are not updated. An application can explicitly db.get() the value of a ReferenceProperty (which is a Key) to test whether the referenced entity exists.
Deleting an entity does not delete entities referred to by a ReferenceProperty.
Introduction to reference properties.
http://code.google.com/appengine/docs/datastore/entitiesandmodels.html#References
References
A property value can contain the key of another entity. The value is a Key instance.
# To fetch and iterate over every SecondModel entity that refers to the
# FirstModel instance obj1:
for obj in obj1.firstmodel_set:
# ...
The name of the back-reference property defaults to modelname_set (with the name of the model class in lowercase letters, and "_set" added to the end), and can be adjusted using the collection_name argument to the ReferenceProperty constructor.
Automatic referencing and dereferencing of model instances, type checking and back-references are only available using the ReferenceProperty model property class. Keys stored as values of Expando dynamic properties or ListProperty values do not have these features.
- http://groups.google.com/group/google-appengine/browse_thread/thread/e9464ceb131c726f?hl=en
http://blog.arbingersys.com/2008/04/google-app-engine-better-many-to-many.html - http://cluebin.appspot.com/pasted/25
- The more entity groups your application has―that is, the more root entities there are―the more efficiently the datastore can distribute the entity groups across datastore nodes. Better distribution improves the performance of creating and updating data. Also, multiple users attempting to update entities in the same entity group at the same time will cause some users to retry their transactions, possibly causing some to fail to commit changes. Do not put all of the application's entities under one root.
- A good rule of thumb for entity groups is that they should be about the size of a single user's worth of data or smaller.
- Entity groups do not have a significant impact on the speed of queries.
2008年5月14日水曜日
テーブル 分解
a = "abc</tr>efg</tr>aaa" imgList += "</table>" rr = range(0, len(imgData.split('</tr>'))-1 ) for r in rr: | abc</tr>efg</tr>aaa |
削除、一括登録
http://code.google.com/appengine/docs/datastore/creatinggettinganddeletingdata.html
class editBlog(BaseRequestHandler):
def get(self):
cmd = self.request.get('cmd')
if cmd == 'delete':
q = db.GqlQuery("SELECT * FROM Blog" )
results = q.fetch(100)
# db.delete(results)
for result in results:
result.delete()
self.redirect('/_ah/admin/datastore?kind=Blog')
# self.redirect('/helloworld/')
Deleting an entity does not change any Key values in the datastore that may have referred to the entity. If your application may attempt to de-reference a Key value for a deleted entity, the application should do so using db.get(), then test the return value before accessing properties.
- get(keys)
- Gets the entity or entities for the given key or keys, of any Model.
- Arguments:
-
If one Key is provided, the return value is an instance of the appropriate Model class, or None if no entity exists with the given Key. If a list of Keys is provided, the return value is a corresponding list of model instances, with None values when no entity exists for a corresponding Key. See also Model.get().
-
Deleting an entity that is an ancestor for other entities does not affect the other entities. As long as the application does not depend on the existence of the ancestor to build keys for the descendant entities, the application can still access the descendants.
ループによる登録が思うように動作しない
トランザクションの問題ではないようなのだが。
http://code.google.com/appengine/docs/datastore/transactions.html
データストア Property
http://code.google.com/appengine/docs/datastore/typesandpropertyclasses.html#StringProperty
- class StringProperty(verbose_name=None, multiline=False, ...)
-
A short string property. Takes a Python str or unicode (basestring) value of 500 bytes or less.
500バイト以下
StringProperty property values are indexed, and can be used in filters and sort orders.
インデックスによるフィルタ、並び替え可能
If multiline is False, then the value cannot include linefeed characters. The djangoforms library uses this to enforce a difference between text fields and textarea fields in the data model, and others can use it for a similar purpose.
multiline=True にすると LF(Line Feed)を含めることができる
Value type: str or unicode
- class TextProperty()
-
A long string.
Unlike StringProperty, a TextProperty value can be more than 500 bytes long. However, TextProperty values are not indexed, and cannot be used in filters or sort orders.
- 500 バイト以上対応
フィルタはつかえない
検索条件にするものには向かないTextProperty values store text with a text encoding. For binary data, use BlobProperty.
Value type: Text
- class DateTimeProperty(verbose_name=None, auto_now=False, auto_now_add=False, ...)
-
A date and time property.
If auto_now is True, the property value is set to the current time whenever the model instance is stored in the datastore, overwriting the property's previous value. This is useful for tracking a "last modified" date and time for a model instance.
If auto_now_add is True, the property value is set to the current time the first time the model instance is stored in the datastore, unless the property has already been assigned a value. This is useful for storing a "created" date and time for a model instance.
BadValueError: Property entry_date must be a datetime
Date-time values are stored as and returned using the UTC time zone. See datetime.datetime for a discussion of how to manage time zones.
Value type: datetime.datetime
datetime に文字列の日時をいきなり代入しようとすると以下のエラーとなる。BadValueError: Property entry_date must be a datetime
strptime での対応が必要。
yymm = '2008-05-10 22:22:22'
ydate = datetime.datetime.strptime(yymm, '%Y-%m-%d %H:%M:%S')
print ydateフォーマット文字 説明 出力例 a 'a.m.' または 'p.m.' (Associated Press に合わせるため,'.' が入っている点が PHP と違います). 'a.m.' A 'AM' または 'PM' です. 'AM' B 実装されていません. d 月の中の日. 2 桁のゼロ詰めです. '01' から '31' D 週の中の日. 3 文字のテキスト形式です. 'Fri' f 12 時間表記の時と分.ただし,ゼロ分の場合には表示しません.独自の拡張です. '1', '1:30' F 月名を長いテキスト形式で表したものです. 'January' g 12 時間表記の時.ゼロ詰めはしません. '1' から '12' G 24 時間表記の時.ゼロ詰めはしません. '0' から '23' h 12 時間表記の時です. '01' から '12' H 24 時間表記の時です. '00' から '23' i 分です. '00' から '59' I 実装されていません. j 月の中の日.ゼロ詰めしません. '1' から '31' l 週の中の曜日.長いテキスト形式です. 'Friday' L 閏年かどうかを表すブール値です. True``または``False m 月です.2 桁でゼロ詰めしたものです. '01' から '12' M 月です.3 文字のテキスト形式です. 'Jan' n 月です.ゼロ詰めしません. '1' から '12' N Associated Press スタイルの月の省略表記です.独自の拡張です. 'Jan.', 'Feb.', 'March', 'May' O グリニッジ標準時からの時差です. '+0200' P 時刻です.12 時間表記の時,分,そして 'a.m.'/'p.m.' です.分がゼロの場合には省略され,必要に応じて'midnight' または 'noon' になります.独自の拡張です. '1 a.m.', '1:30 p.m.', 'midnight', 'noon', '12:30 p.m.' r RFC 822 に従ったフォーマットの日時です. 'Thu, 21 Dec 2000 16:01:07 +0200' s 秒です. 2 桁のゼロ詰めです. '00' から '59' S 月の中の日につける 2 文字の序数接尾辞です. 'st', 'nd', 'rd' or 'th' t 月の日数です. 28 から 31 T 計算機のタイムゾーン設定です. 'EST', 'MDT' U 実装されていません. w 週の中の曜日です.ゼロ詰めしません. '0' (Sunday) to '6' (Saturday) W ISO-8601 に従った年の中の週番号です.週は月曜日から始まります. 1, 23 y 2 桁の年です. '99' Y 4 桁の年です. '1999' z 年の中の日 0 から 365 Z タイムゾーンオフセットを秒であらわしたものです.UTC よりも西側のタイムゾーン値は全て負の値になり,東側の値は常に正になります. -43200 から 43200 例:
It is {% now "jS F Y H:i" %}
フォーマット文字列中で普通の文字列を使いたければ,バックスラッシュでエスケープできます.下の例では,"f" が時刻を表すフォーマット指定子として解釈されないようにエスケープしています. "o" はフォーマット指定子ではないのでエスケープしていません:
It is the {% now "jS o\f F" %}
このテンプレートは "It is the 4th of September" になります.
2008年5月13日火曜日
Calendar
もあるけれども、 range を使うのがわかりやすいか。
| [2007] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] |
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 wrongutility 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')
returns isn't a Unicode string either, so you need to convert it to
Unicode. Eg:
urllib.unquote(q).decode("utf8") + u"\uFFFD"
Swift UI チュートリアル Loading watchOS が終わらない?
Loading watchOS が終わらない? ディスク容量の残量が少ないので不要なシュミレーターを削除したとこころ watchOSのものが全部なくなってしまっていた。 WatchOS を削除して再度インストールしても復活せず。 Create a new simulator で ...
-
1. get_or_insert 自体がトランザクションなのでこれを含めたトランザクションを 作成しようとするとエラーとなる。 File "C:\Program Files\Google\google_appengine\google\appengine\api\...
-
新しいXcodeが使いたかったので MacOS15(Sequoia) にアップグレードしたところ、やはりApacheでPHPが動かなくなっていた。 結論としては brew, openssl, php, httpd を全て再度インストールしたところ動くようになった。 以下、作業ロ...
-
Apache が動かなくなった (MacOS 13.6.7) /var/log/apache2/access_log も error_log も出力されなくなっている $ sudo apachectl start すると以下のようなエラーとなった。 Load failed: ...