Commits

Anonymous committed edb4c96

Initial import.

  • Participants

Comments (0)

Files changed (2)

+# use glob syntax.
+syntax: glob
+
+*.elc
+*.pyc
+*.swp
+*.mo
+*~
+*.orig
+.google_appengine
+**/.svn
+gaebar
+settings.py
+
+syntax: regexp
+(.*/)?\#[^/]*\#$
+(.*/)?\.\#[^/]*$

django-hack-a-thon-get-handson.txt

+
+"Starting app-engine-patch" at 4/25 Django 勉強会 GAE hands on
+
+1. app-engine-patch を入手
+
+何はともあれ入手しましょう。
+http://code.google.com/p/app-engine-patch/
+から app-engine-patch-sample-1.0.zip をダウンロードします。
+
+解凍した app-engine-patch-sample ディレクトリをコピーして使いましょう。
+
+$ cp -r app-engine-patch-sample handson
+
+
+2. このままで色々動かす事ができます。興味があったら試してみましょう。
+
+$ cd handson
+$ python manage.py runserver
+
+
+3. 設定ファイルを少し直しましょう。
+* app.yaml の application を自分の app slot 名に変更します。
+また、下記のように admin 用の handler も足しておきましょう。
+------------------------------------------------------------------------------
+handlers:
+- url: /media
+  static_dir: _generated_media
+- url: /admin/.*
+  script: common/appenginepatch/main.py
+  login: admin
+- url: /.*
+  script: common/appenginepatch/main.py
+------------------------------------------------------------------------------
+
+* このハンズオンでは Google Account 認証を使うように変更します。
+  settings.py の編集をしましょう。
+  まずは SECRET_KEY に秘密の文字列を入れます。
+  次に middleware のところで下記のモジュールをコメントアウトして
+  'django.contrib.auth.middleware.AuthenticationMiddleware'
+  下記のモジュールを有効にします。
+  'ragendja.auth.middleware.GoogleAuthenticationMiddleware'
+  最後に認証に使用するモジュールを指定します。
+  (コメントアウトされているのをアンコメントするだけです)
+  AUTH_USER_MODULE = 'ragendja.auth.google_models'
+  AUTH_ADMIN_MODULE = 'ragendja.auth.google_admin'
+
+
+4. さらに不必要なアプリケーションを無効にします。
+* settings.py の INSTALLED_APPS にて myapp, registration, mediautils を
+  外します。
+* それらのディレクトリは消してしましましょう
+$ rm -rf myapp registration
+
+* mac で X-MAC-JAPANESE 関係の Exception が出る場合
+settings.py の冒頭で下記のようにします
+------------------------------------------------------------------------------
+def register_x_max_ja():
+    "workaround of 'Caught an exception while rendering: unknown encoding: X-MAC-JAPANESE'"
+    import codecs
+    from encodings.utf_8 import getregentry
+    codecs.register(lambda name: getregentry() if name == 'x-mac-japanese' else None)
+
+register_x_max_ja()
+------------------------------------------------------------------------------
+
+
+5. poll アプリケーションを作成していきましょう。
+
+* manage.py を使って poll アプリケーションを作成します。
+$ python manage.py startapp polls
+
+* urls.py を下記のように直します。
+------------------------------------------------------------------------------
+ -*- coding: utf-8 -*-
+from django.conf.urls.defaults import *
+from ragendja.urlsauto import urlpatterns
+from ragendja.auth.urls import urlpatterns as auth_patterns
+from django.contrib import admin
+
+admin.autodiscover()
+
+handler500 = 'ragendja.views.server_error'
+
+urlpatterns = auth_patterns + patterns('',
+    ('^admin/(.*)', admin.site.root),
+    (r'^polls/', include('polls.urls')),
+) + urlpatterns
+------------------------------------------------------------------------------
+
+* polls/urls.py を作成します。
+------------------------------------------------------------------------------
+# -*- coding: utf-8 -*-
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns(
+  'polls.views',
+  url(r'^$', 'top', name='polls_top'),
+)
+------------------------------------------------------------------------------
+
+* polls/views.py にメソッドを書きます。
+------------------------------------------------------------------------------
+# -*- coding: utf-8 -*-
+from django.http import HttpResponse, HttpResponseRedirect
+from django.utils.translation import ugettext as _
+from ragendja.template import render_to_response
+
+def top(request):
+  return HttpResponse("Hello app-engine-patch!")
+------------------------------------------------------------------------------
+
+この状態で runserver すれば http://localhost:8080/polls/ で Hello メッ
+セージが見られます。
+
+
+6. Model を書きましょう。
+* polls/models.py を下記のようにします。
+------------------------------------------------------------------------------
+# -*- coding: utf-8 -*-
+from django.utils.translation import ugettext_lazy as _
+from google.appengine.ext import db
+import datetime
+
+class Poll(db.Model):
+    question = db.StringProperty(verbose_name='question', required=True)
+    pub_date = db.DateTimeProperty(verbose_name='date published',
+                                   required=True)
+    def __unicode__(self):
+        return self.question
+
+    def was_published_today(self):
+        return self.pub_date.date() == datetime.date.today()
+
+class Choice(db.Model):
+    poll = db.ReferenceProperty(Poll)
+    choice = db.StringProperty(verbose_name='choice', required=True)
+    votes = db.IntegerProperty(verbose_name='votes', required=True,
+                               default=0)
+    def __unicode__(self):
+        return self.choice
+------------------------------------------------------------------------------
+
+* これで manage.py shell できます
+$ python manage.py shell
+In [1]: from polls.models import Poll, Choice
+In [2]: Poll.all().get()
+(None)
+In [4]: import datetime
+In [5]: p = Poll(question="What's up?", pub_date=datetime.datetime.now())
+In [6]: p.put()
+Out[6]: datastore_types.Key.from_path('polls_poll', 2L, _app=u'tm-test')
+In [9]: p.key().id()
+Out[9]: 2L
+In [12]: p.question
+Out[12]: "What's up?"
+In [13]: p.pub_date 
+Out[13]: datetime.datetime(2009, 4, 22, 3, 8, 41, 420652)
+In [14]: p.pub_date = datetime.datetime(2007, 4, 1, 0, 0)
+In [15]: p.put()
+Out[15]: datastore_types.Key.from_path('polls_poll', 2L, _app=u'tm-test')
+In [17]: Poll.all().fetch(10)
+Out[17]: [Poll(**{'question': u"What's up?", 'pub_date': \
+	 datetime.datetime(2007, 4, 1, 0, 0)})]
+
+
+7. Admin サイトを使います
+* polls/admin.py を下記のように作成します。
+------------------------------------------------------------------------------
+from polls.models import Poll
+from django.contrib import admin
+
+admin.site.register(Poll)
+------------------------------------------------------------------------------
+* settings.py の INSTALLED_APPS に 'polls' を追加しましょう。
+
+これで http://localhost:8000/admin にアクセスすれば Django の Admin が
+使えます!
+
+* ちょっと変更してみましょう。admin.site.register(Poll) の行を下記で置
+  き換えます。
+------------------------------------------------------------------------------
+class PollAdmin(admin.ModelAdmin):
+    fields = ['pub_date', 'question']
+
+admin.site.register(Poll, PollAdmin)
+------------------------------------------------------------------------------
+
+どうなりましたか?
+
+* 今度は下記のように置き換えてみましょう。
+------------------------------------------------------------------------------
+class PollAdmin(admin.ModelAdmin):
+    fieldsets = [
+        (None,               {'fields': ['question']}),
+        ('Date information', {'fields': ['pub_date']}),
+    ]
+
+admin.site.register(Poll, PollAdmin)
+------------------------------------------------------------------------------
+
+* もう一つのパターンです
+------------------------------------------------------------------------------
+class PollAdmin(admin.ModelAdmin):
+    fieldsets = [
+        (None,               {'fields': ['question']}),
+        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
+    ]
+------------------------------------------------------------------------------
+
+* Choice を登録しましょう。polls/admin.py を下記のようにします。
+------------------------------------------------------------------------------
+from polls.models import Poll, Choice
+from django.contrib import admin
+
+class ChoiceInline(admin.StackedInline):
+    model = Choice
+    extra = 3
+
+class PollAdmin(admin.ModelAdmin):
+    fieldsets = [
+        (None,               {'fields': ['question']}),
+        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
+    ]
+    inlines = [ChoiceInline]
+
+admin.site.register(Poll, PollAdmin)
+admin.site.register(Choice)
+------------------------------------------------------------------------------
+
+これで Choice の編集画面では Poll を選べるように、また Poll にも
+Choice を追加できるようになりました。
+
+* StackedInline の代わりに TabularInline も使えます。
+------------------------------------------------------------------------------
+class ChoiceInline(admin.TabularInline):
+------------------------------------------------------------------------------
+
+* Poll の一覧で表示する項目を変更してみましょう。まずは PollAdmin を編
+  集します。
+------------------------------------------------------------------------------
+class PollAdmin(admin.ModelAdmin):
+    # ...
+    list_display = ('question', 'pub_date', 'was_published_today')
+------------------------------------------------------------------------------
+
+* polls/models.py の was_published_today に description を付けます。
+------------------------------------------------------------------------------
+class Poll(db.Model):
+    # ...
+    def was_published_today(self):
+        return self.pub_date.date() == datetime.date.today()
+    was_published_today.short_description = 'Published today?'
+------------------------------------------------------------------------------
+
+* PollAdmin に機能を足しましょう。
+------------------------------------------------------------------------------
+class PollAdmin(admin.ModelAdmin):
+    # ...
+    list_filter = ['pub_date']
+    search_fields = ['question']
+    date_hierarchy = 'pub_date'
+------------------------------------------------------------------------------
+残念ながら、これらの機能は今は動かないようです。
+
+
+8. urls.py と view を書きましょう
+
+* polls/urls.py
+------------------------------------------------------------------------------
+# -*- coding: utf-8 -*-
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns(
+  'polls.views',
+  url(r'^$', 'index', name='polls_index'),
+  url(r'^(?P<poll_id>\d+)/$', 'detail', name='polls_detail'),
+  url(r'^(?P<poll_id>\d+)/results/$', 'results', name='polls_results'),
+  url(r'^(?P<poll_id>\d+)/vote/$', 'vote', name='polls_vote'),
+)
+------------------------------------------------------------------------------
+
+* index を作ります。polls/views.py 下記のように追加します。
+------------------------------------------------------------------------------
+from polls.models import Poll
+
+def index(request):
+    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
+    output = ', '.join([p.question for p in latest_poll_list])
+    return HttpResponse(output)
+
+def detail(request, poll_id):
+    pass
+
+def vote(request, poll_id):
+    pass
+
+def results(request, poll_id):
+    pass
+------------------------------------------------------------------------------
+
+* テンプレートを使うように変更します。
+------------------------------------------------------------------------------
+...
+from django.template import Context, loader
+
+def index(request):
+    latest_poll_list = Poll.all().order('-pub_date').fetch(5)
+    t = loader.get_template('polls/index.html')
+    c = Context({
+        'latest_poll_list': latest_poll_list,
+    })
+    return HttpResponse(t.render(c))
+------------------------------------------------------------------------------
+
+ここでアクセスすると TemplateDoesNotExist が発生しますね。
+
+* テンプレートを書きましょう。polls/templates/index.html を書きます。
+------------------------------------------------------------------------------
+{% if latest_poll_list %}
+    <ul>
+    {% for poll in latest_poll_list %}
+        <li><a href="{% url polls_detail poll_id=poll.key.id %}">
+	    {{ poll.question }}
+	    </a>
+	</li>
+    {% endfor %}
+    </ul>
+{% else %}
+    <p>No polls are available.</p>
+{% endif %}
+------------------------------------------------------------------------------
+
+* ショートカットを使います。polls/views.py で下記のようにします。
+------------------------------------------------------------------------------
+from django.shortcuts import render_to_response
+# ...
+def index(request):
+    latest_poll_list = Poll.all().order('-pub_date').fetch(5)
+    return render_to_response('polls/index.html',
+                              {'latest_poll_list': latest_poll_list})
+------------------------------------------------------------------------------
+
+* detail view を書きましょう。polls/views.py
+------------------------------------------------------------------------------
+from ragendja.dbutils import get_object_or_404
+...
+def detail(request, poll_id):
+    p = get_object_or_404(Poll, id=long(poll_id))
+    return render_to_response('polls/detail.html', {'poll': p})
+------------------------------------------------------------------------------
+
+* polls/templates/detail.html
+------------------------------------------------------------------------------
+<h1>{{ poll.question }}</h1>
+<ul>
+{% for choice in poll.choice_set %}
+    <li>{{ choice.choice }}</li>
+{% endfor %}
+</ul>
+------------------------------------------------------------------------------
+
+
+9. フォームを使用します。
+
+* polls/templates/detail.html を変更します。
+------------------------------------------------------------------------------
+<h1>{{ poll.question }}</h1>
+
+{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
+
+<form action="{% url polls_vote poll_id=poll.key.id %}" method="post">
+{% for choice in poll.choice_set %}
+    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.key.id }}" />
+    <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
+{% endfor %}
+<input type="submit" value="Vote" />
+</form>
+------------------------------------------------------------------------------
+
+* polls/views.py で vote を受け付けるように、また結果表示もしましょう。
+------------------------------------------------------------------------------
+from polls.models import Poll, Choice
+# ...
+from django.core.urlresolvers import reverse
+from google.appengine.ext import db
+# ...
+
+def vote(request, poll_id):
+    p = get_object_or_404(Poll, id=long(poll_id))
+    try:
+        selected_choice = p.choice_set.filter(
+            '__key__ =',
+            db.Key.from_path('polls_choice',
+                             long(request.POST['choice']))).get()
+        if selected_choice is None:
+          raise Exception('Specified choice not found.')
+    except Exception, e:
+        import logging
+        logging.info(e)
+        return render_to_response('polls/detail.html', {
+            'poll': p,
+            'error_message': "You didn't select a choice.",
+        })
+    def countup_vote(key):
+      c = Choice.get(key)
+      c.votes += 1
+      c.put()
+    db.run_in_transaction(countup_vote, selected_choice.key())
+    return HttpResponseRedirect(reverse('polls.views.results',
+                                        args=(p.key().id(),)))
+
+def results(request, poll_id):
+    p = get_object_or_404(Poll, id=long(poll_id))
+    return render_to_response('polls/results.html', {'poll': p})
+------------------------------------------------------------------------------
+
+* polls/templates/results.html
+------------------------------------------------------------------------------
+<h1>{{ poll.question }}</h1>
+
+<ul>
+{% for choice in poll.choice_set %}
+    <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
+{% endfor %}
+</ul>
+------------------------------------------------------------------------------
+
+******************************************************************************
+Polls アプリケーションが一応完成です。これで今日のハンズオンは終わりで
+す。もし時間があったらさらに機能を足してみましょう。
+******************************************************************************