Archive for 1月 3rd, 2011
1月 3rd, 2011 by admin
2,3か月前に作成したサーバの監視アプリのソースコードを紹介します。5分間隔で数百件程度のURLにリクエストを投げ、そのレスポンスタイムを取得するだけの単純なアプリなので、機能としては単純なのですが、性能面の制約に苦しみました。今でこそ、CronやTaskQueueから実行したリクエストは、最大で10分間実行できますが、当時は30秒制限があったため、容易に制限時間を超えてしまったのです。平均1秒だとしても30秒の時間制限内には到底処理が終わりません。いろいろ考えた末、Cron関数内で5URLずつまとめてTaskQueueに投げ込むことにしました。その結果、当時の厳しい実行時間制約(30秒)の中、無事に要件を満たすことができました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Cron(webapp.RequestHandler):
def get(self):
size = 5
sites = db.GqlQuery("SELECT * FROM Site ORDER BY date DESC")
for i in range(0, sites.count(), size): # i = 0, 5, 10, 15, ......
params = {}
for j in range(0, size): #j = 0, 1, 2, 3, 4
if i + j >= sites.count():
break
params["url"+str(j)] = sites[i+j].url
taskqueue.add(url='/worker', params = params) # taskqueueにタスクを追加
class Worker(webapp.RequestHandler):
def post(self):
if(int(self.request.headers.environ['HTTP_X_APPENGINE_TASKRETRYCOUNT']) > 0):
return # エラー発生時の、リトライ防止
for key in self.request.arguments():
try:
url = self.request.get(key)
fetchAndLog(url) # レスポンスタイムの測定と記録。5秒を超えると例外を投げる。
except:
pass |
1月 3rd, 2011 by admin
python-blog-systemで、投稿内に長いURLを記入した際に、45文字目までしか表示しないように変更しました。
変更前
1 2 3
| import re
def linkURLs(str):
return re.sub(r'([^"]|^)(https?|ftp)(://[\w:;/.?%#&=+-]+)', r'\1<a href="\2\3">\2\3</a>', str) |
subの第2引数を正規表現で指定しています。
変更後
1 2 3 4 5
| import re
def urlReplacer(match, limit = 45):
return '<a href="%s" target="_blank">%s</a>' % (match.group(), match.group()[:limit] + ('...' if len(match.group()) > limit else ''))
def linkURLs(str):
return re.sub(r'([^"]|^)(https?|ftp)(://[\w:;/.?%#&=+-]+)', urlReplacer, str) |
subの第2引数を、コールバックで指定している。URLが45文字を超えた場合は、45文字目までで打ち切り、末尾に…を付加しています。
1月 3rd, 2011 by admin
python-blog-systemにコメント削除機能を実装しました。コメント投稿時に入力したパスワードを指定した場合のみ、コメントの削除が実行されます。投稿時にパスワードを指定しなかった場合は、削除できないようにしました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #削除ボタンの表示部分
delbutton = u"""
<div style="float:right">
<form method="post" name="form" action="/deleteComment/%(key)s">
<input type="text" name="delpass" class="delcommentpassword"/>
<input type="button" onclick="if(confirm('本当に削除しますか?'))form.submit()" value="削除" class="delcommentbutton"/>
</div>""" % {"key":comment.key()}
#実際の削除処理
class DeleteCommentHandler(AuthHandler):
def post(self, key):
comment = Comment.get(key)
entry_key = comment.entry.key() # コメント先の記事に戻るために、削除前に記事IDを取得
if self.request.get("delpass") == comment.delpass and comment.delpass != "":
db.delete(comment)
self.redirect('/entry/%s' % entry_key) |
1月 3rd, 2011 by admin
tuple、list、dictなどの要素指定できるオブジェクト以外に対して、要素指定でアクセスしようとすると、”TypeError: ‘Key’ object is unsubscriptable”となるようです。下記のようなコードを実行して、このエラーを発生させてしまいました。
1
| "Key is %(key)s" % something.key() |
名前指定で文字列を置換する場合は、dictで値を渡しましょう。
1
| "Key is %(key)s" % {"key" : something.key()} |
発生したエラー
1 2 3 4 5 6 7 8
| Traceback (most recent call last):
File "C:\Program Files\Google\google_appengine\google\appengine\ext\webapp\__init__.py", line 515, in __call__
handler.get(*groups)
File "C:\python\relation\main.py", line 137, in get
printEntry(self, entry, commentDetail = True)
File "C:\python\relation\main.py", line 164, in printEntry
</div>""" % comment.key()
TypeError: 'Key' object is unsubscriptable |
1月 3rd, 2011 by admin
現在作成中のブログシステムで1対多のデータ構造を構築したので紹介しておく。1つの投稿(Entry)に対して、コメント(Comment)は複数設定できる。こういうデータ構造は、Commentオブジェクトに、Entryオブジェクトへの参照(db.ReferenceProperty)を持たせることで実現できる。collection_name=’comments’と指定しているため、EntryからCommentを取得する場合は、entry.commentsと記述すればよい。そして時系列に並べるためにorder(‘datetime’)でソートしている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| for comment in entry.comments.order('datetime'):
pass
class Entry(db.Model):
title = db.StringProperty(default = "")
body = db.TextProperty(default = "")
tags = db.ListProperty(db.Key)
datetime = db.DateTimeProperty(auto_now_add = True)
@property
def formattedDatetimeInJST(self):
return (self.datetime + datetime.timedelta(hours=9)).strftime("%Y-%m-%d %H:%M:%S")
def tagStr(self):
return " ".join([Tag.get(x).tag for x in self.tags])
class Comment(db.Model):
comment = db.TextProperty(default = "")
entry = db.ReferenceProperty(Entry, collection_name = 'comments')
user = db.UserProperty()
datetime = db.DateTimeProperty(auto_now_add = True)
delpass = db.TextProperty()
nickname = db.TextProperty() |
|
|