Commits

Anonymous committed bd7ca88

Renamed a file.

Comments (0)

Files changed (2)

django-hack-a-thon-gae-handson.rst

+==============================================================
+"Starting app-engine-patch" at 4/25 Django 勉強会 GAE hands on
+==============================================================
+
+app-engine-patch を入手
+-----------------------
+
+何はともあれ入手しましょう。
+http://code.google.com/p/app-engine-patch/
+から app-engine-patch-sample-1.0.zip をダウンロードします。
+
+解凍した app-engine-patch-sample ディレクトリをコピーして使いましょう。
+
+.. code-block:: console
+
+    $ cp -r app-engine-patch-sample handson
+
+アプリを動かす
+--------------
+
+このままで色々動かす事ができます。興味があったら試してみましょう。
+
+.. code-block:: console
+
+    $ cd handson
+    $ python manage.py runserver
+
+設定ファイルを少し直しましょう。
+---------------------------------------------
+
+* 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'
+
+さらに不必要なアプリケーションを無効にします。
+
+* settings.py の INSTALLED_APPS にて myapp, registration, mediautils を
+  外します。
+* それらのディレクトリは消してしましましょう
+    
+.. code-block:: console
+
+    $ rm -rf myapp registration
+
+mac で X-MAC-JAPANESE 関係の Exception が出る場合
+-------------------------------------------------
+
+settings.py の冒頭で下記のようにします
+
+.. code-block:: python
+
+    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()
+
+poll アプリケーションを作成していきましょう。
+---------------------------------------------
+
+* manage.py を使って poll アプリケーションを作成します。
+
+.. code-block:: console
+
+    $ python manage.py startapp polls
+
+* urls.py を下記のように直します。
+
+.. code-block:: python
+
+    # -*- 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 を作成します。
+
+.. code-block:: python
+
+    # -*- coding: utf-8 -*-
+    from django.conf.urls.defaults import *
+
+    urlpatterns = patterns(
+      'polls.views',
+      url(r'^$', 'top', name='polls_top'),
+    )
+
+* polls/views.py にメソッドを書きます。
+
+.. code-block:: python
+
+    # -*- 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:8000/polls/ で Hello メッ
+セージが見られます。
+
+
+Model を書きましょう。
+------------------------
+
+* polls/models.py を下記のようにします。
+
+.. code-block:: python
+
+    # -*- 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)})]
+
+Admin サイトを使います
+----------------------
+
+* polls/admin.py を下記のように作成します。
+
+.. code-block:: python
+
+    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) の行を下記で置
+  き換えます。
+
+.. code-block:: python
+
+    class PollAdmin(admin.ModelAdmin):
+        fields = ['pub_date', 'question']
+
+    admin.site.register(Poll, PollAdmin)
+
+どうなりましたか?
+
+* 今度は下記のように置き換えてみましょう。
+
+.. code-block:: python
+
+    class PollAdmin(admin.ModelAdmin):
+        fieldsets = [
+            (None,               {'fields': ['question']}),
+            ('Date information', {'fields': ['pub_date']}),
+        ]
+
+    admin.site.register(Poll, PollAdmin)
+
+* もう一つのパターンです
+
+.. code-block:: python
+
+    class PollAdmin(admin.ModelAdmin):
+        fieldsets = [
+            (None,               {'fields': ['question']}),
+            ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
+        ]
+
+* Choice を登録しましょう。polls/admin.py を下記のようにします。
+
+.. code-block:: python
+
+    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 も使えます。
+
+.. code-block:: python
+
+    class ChoiceInline(admin.TabularInline):
+
+* Poll の一覧で表示する項目を変更してみましょう。まずは PollAdmin を編
+  集します。
+
+.. code-block:: python
+
+    class PollAdmin(admin.ModelAdmin):
+        # ...
+        list_display = ('question', 'pub_date', 'was_published_today')
+
+* polls/models.py の was_published_today に description を付けます。
+
+.. code-block:: python
+
+    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 に機能を足しましょう。
+
+.. code-block:: python
+
+    class PollAdmin(admin.ModelAdmin):
+        # ...
+        list_filter = ['pub_date']
+        search_fields = ['question']
+        date_hierarchy = 'pub_date'
+
+残念ながら、これらの機能は今は動かないようです。
+
+
+urls.py と view を書きましょう
+------------------------------
+
+* polls/urls.py
+
+.. code-block:: python
+
+    # -*- 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 下記のように追加します。
+
+.. code-block:: python
+
+    from polls.models import Poll
+
+    def index(request):
+        latest_poll_list = Poll.all().order('-pub_date').fetch(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
+
+* テンプレートを使うように変更します。
+
+.. code-block:: python
+
+    # ...
+    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 を書きます。
+
+.. code-block:: 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 で下記のようにします。
+  ragendja のショートカットもありますが、ここでは django のものを使いま
+  す。
+
+.. code-block:: python
+
+    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
+
+.. code-block:: python
+
+    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
+
+.. code-block:: html
+
+    <h1>{{ poll.question }}</h1>
+    <ul>
+    {% for choice in poll.choice_set %}
+        <li>{{ choice.choice }}</li>
+    {% endfor %}
+    </ul>
+
+フォームを使用します。
+--------------------------
+
+* polls/templates/detail.html を変更します。
+
+.. code-block:: 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 を受け付けるように、また結果表示もしましょう。
+
+.. code-block:: python
+
+    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
+
+.. code-block:: 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 アプリケーションが一応完成です。これで今日のハンズオンは終わりで
+す。もし時間があったらさらに機能を足してみましょう。
+
+サーバへのデプロイ
+------------------
+
+* サーバにデプロイするのはとても簡単です
+
+.. code-block:: console
+
+    $ python manage.py update
+
+* 初めはエラーになる事もありますが、サーバ側でインデックスの生成が終わ
+  るとアクセスできるようになります。
+
+* もしかすると投票がうまくいかないかもしれません。その時はサーバの管理
+  コンソールでログを見ると index が無いというようなエラーが出ている場合
+  があります。そのときはログに表示された index 定義を index.yaml に書い
+  てアップロードすると動くようになります。

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

-==============================================================
-"Starting app-engine-patch" at 4/25 Django 勉強会 GAE hands on
-==============================================================
-
-app-engine-patch を入手
------------------------
-
-何はともあれ入手しましょう。
-http://code.google.com/p/app-engine-patch/
-から app-engine-patch-sample-1.0.zip をダウンロードします。
-
-解凍した app-engine-patch-sample ディレクトリをコピーして使いましょう。
-
-.. code-block:: console
-
-    $ cp -r app-engine-patch-sample handson
-
-アプリを動かす
---------------
-
-このままで色々動かす事ができます。興味があったら試してみましょう。
-
-.. code-block:: console
-
-    $ cd handson
-    $ python manage.py runserver
-
-設定ファイルを少し直しましょう。
----------------------------------------------
-
-* 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'
-
-さらに不必要なアプリケーションを無効にします。
-
-* settings.py の INSTALLED_APPS にて myapp, registration, mediautils を
-  外します。
-* それらのディレクトリは消してしましましょう
-    
-.. code-block:: console
-
-    $ rm -rf myapp registration
-
-mac で X-MAC-JAPANESE 関係の Exception が出る場合
--------------------------------------------------
-
-settings.py の冒頭で下記のようにします
-
-.. code-block:: python
-
-    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()
-
-poll アプリケーションを作成していきましょう。
----------------------------------------------
-
-* manage.py を使って poll アプリケーションを作成します。
-
-.. code-block:: console
-
-    $ python manage.py startapp polls
-
-* urls.py を下記のように直します。
-
-.. code-block:: python
-
-    # -*- 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 を作成します。
-
-.. code-block:: python
-
-    # -*- coding: utf-8 -*-
-    from django.conf.urls.defaults import *
-
-    urlpatterns = patterns(
-      'polls.views',
-      url(r'^$', 'top', name='polls_top'),
-    )
-
-* polls/views.py にメソッドを書きます。
-
-.. code-block:: python
-
-    # -*- 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:8000/polls/ で Hello メッ
-セージが見られます。
-
-
-Model を書きましょう。
-------------------------
-
-* polls/models.py を下記のようにします。
-
-.. code-block:: python
-
-    # -*- 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)})]
-
-Admin サイトを使います
-----------------------
-
-* polls/admin.py を下記のように作成します。
-
-.. code-block:: python
-
-    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) の行を下記で置
-  き換えます。
-
-.. code-block:: python
-
-    class PollAdmin(admin.ModelAdmin):
-        fields = ['pub_date', 'question']
-
-    admin.site.register(Poll, PollAdmin)
-
-どうなりましたか?
-
-* 今度は下記のように置き換えてみましょう。
-
-.. code-block:: python
-
-    class PollAdmin(admin.ModelAdmin):
-        fieldsets = [
-            (None,               {'fields': ['question']}),
-            ('Date information', {'fields': ['pub_date']}),
-        ]
-
-    admin.site.register(Poll, PollAdmin)
-
-* もう一つのパターンです
-
-.. code-block:: python
-
-    class PollAdmin(admin.ModelAdmin):
-        fieldsets = [
-            (None,               {'fields': ['question']}),
-            ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
-        ]
-
-* Choice を登録しましょう。polls/admin.py を下記のようにします。
-
-.. code-block:: python
-
-    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 も使えます。
-
-.. code-block:: python
-
-    class ChoiceInline(admin.TabularInline):
-
-* Poll の一覧で表示する項目を変更してみましょう。まずは PollAdmin を編
-  集します。
-
-.. code-block:: python
-
-    class PollAdmin(admin.ModelAdmin):
-        # ...
-        list_display = ('question', 'pub_date', 'was_published_today')
-
-* polls/models.py の was_published_today に description を付けます。
-
-.. code-block:: python
-
-    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 に機能を足しましょう。
-
-.. code-block:: python
-
-    class PollAdmin(admin.ModelAdmin):
-        # ...
-        list_filter = ['pub_date']
-        search_fields = ['question']
-        date_hierarchy = 'pub_date'
-
-残念ながら、これらの機能は今は動かないようです。
-
-
-urls.py と view を書きましょう
-------------------------------
-
-* polls/urls.py
-
-.. code-block:: python
-
-    # -*- 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 下記のように追加します。
-
-.. code-block:: python
-
-    from polls.models import Poll
-
-    def index(request):
-        latest_poll_list = Poll.all().order('-pub_date').fetch(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
-
-* テンプレートを使うように変更します。
-
-.. code-block:: python
-
-    # ...
-    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 を書きます。
-
-.. code-block:: 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 で下記のようにします。
-  ragendja のショートカットもありますが、ここでは django のものを使いま
-  す。
-
-.. code-block:: python
-
-    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
-
-.. code-block:: python
-
-    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
-
-.. code-block:: html
-
-    <h1>{{ poll.question }}</h1>
-    <ul>
-    {% for choice in poll.choice_set %}
-        <li>{{ choice.choice }}</li>
-    {% endfor %}
-    </ul>
-
-フォームを使用します。
---------------------------
-
-* polls/templates/detail.html を変更します。
-
-.. code-block:: 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 を受け付けるように、また結果表示もしましょう。
-
-.. code-block:: python
-
-    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
-
-.. code-block:: 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 アプリケーションが一応完成です。これで今日のハンズオンは終わりで
-す。もし時間があったらさらに機能を足してみましょう。
-
-サーバへのデプロイ
-------------------
-
-* サーバにデプロイするのはとても簡単です
-
-.. code-block:: console
-
-    $ python manage.py update
-
-* 初めはエラーになる事もありますが、サーバ側でインデックスの生成が終わ
-  るとアクセスできるようになります。
-
-* もしかすると投票がうまくいかないかもしれません。その時はサーバの管理
-  コンソールでログを見ると index が無いというようなエラーが出ている場合
-  があります。そのときはログに表示された index 定義を index.yaml に書い
-  てアップロードすると動くようになります。