templates/404.html, 500.htmlを適当に書き換えておく
これらはdjango.zip内のhtmlに依存していて、その先がmyappに依存しているのでmyappを外すと
NoReverseMatch: Reverse for 'settings.myapp.views.list_people' with arguments '()' and keyword arguments '{}' not found.
などとエラーが出る。
openidgaeで認証
#urls.py urlpatterns = patterns('', ('^openid/', include('openidgae.urls')), ) + auth_patterns + patterns('', ('^admin/(.*)', admin.site.root), 〜
#settings.py LOGIN_URL = '/openid/login/' LOGOUT_URL = '/openid/logout/'
PersonでなくUserを使う
以下は不要
import models persons = models.Person.gql('WHERE openid = :1', openid_url) if persons.count() == 0: p = models.Person() p.openid = openid_url p.ax_dict().update(ax_items) p.sreg_dict().update(sreg_response) p.put() else: p = persons[0] changed = False for key in sreg_response: if not p.sreg_dict().has_key(key) or \ p.sreg_dict()[key] != sreg_response[key]: logging.debug("Setting sreg %s" % key) p.sreg_dict()[key] = sreg_response[key] changed = True for key in ax_items: if not p.ax_dict().has_key(key) or \ p.ax_dict()[key] != ax_items[key]: logging.info("Setting ax %s" % key) p.ax_dict()[key] = ax_items[key] changed = True if changed: p.put()
s = openidgae.get_session(request, response) s.person = p.key() request.openidgae_logged_in_person = p s.put()
s = openidgae.get_session(request, response) if s: s.person = None s.put()
login/logout
URI=djangoのユーザー名として自動的にアカウントを作成している。
User.usernameは30文字以下、という制約は無視。(現在のところ問題になるシーンに遭遇していない)
def pretty(openid): s = openid.replace('http://','').replace('https://','').rstrip('/').split('#')[0] return s def shortname(pretty): rfind = pretty.rfind('/') if rfind and 0 < rfind: return pretty[rfind + 1:] return pretty pretty = pretty(openid) shortname = shortname(pretty) passwd = dummy_passwd(openid) from django.contrib.auth.models import User django_user = User.get_by_key_name(openid) if not django_user: django_user = User(key_name=openid, username=pretty, is_active=True, is_staff=False, is_superuser=False, ) django_user.set_password(passwd) django_user.put() from django.contrib.auth import authenticate, login django_user = authenticate(username=pretty, password=passwd) if django_user is not None: if django_user.is_active: login(request, django_user)
from django.contrib.auth import logout logout(request)
カウンタ
Google App Engine上でスケールするWebアプリを書く
http://www.java-users.jp/contents/events/ccc2009spring/materials/A-3-1.pdf
から改変
class Counter(db.Model): name = db.StringProperty(required=True) count = db.IntegerProperty(required=True, default=0)
class CounterManager(): def get_count_from_db(self, name): total = 0 for counter in Counter.gql('WHERE name= :1', name): total += counter.count return total def get_count(self, name): """ lazy_incr, incr, decr共通の集計関数。 """ from google.appengine.api import memcache count = memcache.get(name) if count == None: count = self.get_count_from_db(name) memcache.set(name, count, consts.COUNTER_EXPIRES) return count def lazy_incr(self, name, value=1): """ 一定時間memcacheでロックして、dbへのwriteを発生させない増加カウンタ。 継続的にコールされる環境での使用を推奨。 精密ではないことに注意。 ロックが解け、その後memcache上のデータが揮発するまでにコールされないと、増加分は失われる。 """ from google.appengine.api import memcache def _set_lock(name): memcache.set('_c:%s' % name, 1, consts.COUNTER_MAX_DELAY_INTERVAL) def _get_lock(name): if None != memcache.get('_c:%s' % name): return True return False count = memcache.get(name) if count == None: db_count = self.get_count(name) count = db_count else: db_count = None memcache.incr(name, delta=value) count += value if not _get_lock(name): _set_lock(name) if db_count == None: db_count = self.get_count_from_db(name) diff = count - db_count if 0 < diff: self._write_db(name, diff) return count def _write_db(self, name, value): """ データストアにcountを書き込む。 エンティティ分散させることでトランザクションロック時間を低減させている。 """ def tr(): import random rand = random.randint(0, consts.COUNTER_DIVISION - 1) counter_name = 'c:%s:%s' % (name, rand) counter = Counter.get_by_key_name(counter_name) if counter == None: counter = Counter(key_name=counter_name, name=name) counter.count += value counter.put() db.run_in_transaction(tr) def incr(self, name, value=1): """ 普通の増加カウンタ。 """ from google.appengine.api import memcache self._write_db(name, value) if memcache.get(name) != None: memcache.incr(name, delta=value) def decr(self, name, value=1): """ 普通の減少カウンタ。 """ from google.appengine.api import memcache db.run_in_transaction(self._write_db, name, -value) if memcache.get(name) != None: memcache.decr(name, delta=value)
アイコン
アップロード
1:1のアスペクト比で中央から切り抜く。
hogeForm = HogeForm(request.POST) icon = hogeForm.cleaned_data['icon'] if icon: try: from google.appengine.api import images img = images.Image(icon.read()) w = img.width h = img.height #crop crop_size = float(min(w, h)) w_crop_rate = crop_size / w h_crop_rate = crop_size / h w_start = (1 - w_crop_rate) / 2 h_start = (1 - h_crop_rate) / 2 w_end = w_start + w_crop_rate h_end = h_start + h_crop_rate img.crop(w_start, h_start, w_end, h_end) #resize crop_size = consts.META_ICON_SIDE_LENGTH img.resize(width=crop_size, height=crop_size) icon = img.execute_transforms(output_encoding=images.JPEG) except: logging.info('Icon update fail.')
返す
response = HttpResponse(icon,
content_type='image/jpeg',
)
LANGUAGESで時間の調整
#templatetags/localdt.py import datetime from django.template import Library register = Library() def localdt(value, lang): lang = lang[1] if lang == 'Japanese': return value + datetime.timedelta(hours=9) else: return value register.filter("localdt", localdt)
{% load localdt %}{{ post.updated|localdt:LANGUAGES|date:"Y m d - P" }}
正の数値を64進数に変換する
def encode_b64(n): table = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_' result = [] temp = n if 0 == temp: result.append('0') else: while 0 < temp: result.append(table[temp % 64]) temp /= 64 return ''.join([x for x in reversed(result)])
64進数から正の数値に変換
def decode_b64(str): table = {"0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "a": 10, "b": 11, "c": 12, "d": 13, "e": 14, "f": 15, "g": 16, "h": 17, "i": 18, "j": 19, "k": 20, "l": 21, "m": 22, "n": 23, "o": 24, "p": 25, "q": 26, "r": 27, "s": 28, "t": 29, "u": 30, "v": 31, "w": 32, "x": 33, "y": 34, "z": 35, "A": 36, "B": 37, "C": 38, "D": 39, "E": 40, "F": 41, "G": 42, "H": 43, "I": 44, "J": 45, "K": 46, "L": 47, "M": 48, "N": 49, "O": 50, "P": 51, "Q": 52, "R": 53, "S": 54, "T": 55, "U": 56, "V": 57, "W": 58, "X": 59, "Y": 60, "Z": 61, "-": 62, "_": 63} result = 0 for i in xrange(len(str)): result *= 64 result += table[str[i]] return result