Commits

Ian Lewis committed 12bccec

Part 2追加 あまり使わない気がするけど

  • Participants
  • Parent commits 0d5e7ac
  • Branches google_login

Comments (0)

Files changed (4)

django-hack-a-thon-get-handson.part2.pdf

Binary file added.

django-hack-a-thon-get-handson.part2.rst

+==============================================================
+"Starting app-engine-patch" Part2
+==============================================================
+----------------
+Google ログイン
+----------------
+
+Googleログインを導入
+-----------------------
+
+GAEではユーザ認証として、Google ログインを使うのが簡単です。
+
+Google users API
+----------------
+
+GAEの基本users APIは簡単なもので、便利です。Googleのユーザがログインしているか
+をチェックできます。ログインとログアウトURLもとれます。ユーザオブジェクト
+についている読み込みせんようです。
+
+現在のユーザをこう使います。::
+
+    from google.appengine.api import users
+
+    user = users.get_current_user()
+    if user:
+        nickname = user.nickname()
+        email = user.email()
+        user_id = user.user_id() # NEW!! ユニークID
+        logout_url = users.get_logout_url("/") # リダイレクトURLを渡す
+        ...
+    else:
+        #Not logged in!!
+        login_url = users.get_login_url("/") # リダイレクトURLを渡す
+        ...
+
+
+Django上で、Google UsersAPIを使う
+---------------------------------
+
+GAEのユーザは読み込み専用し、データが少ないし、Django的な作りができないので、
+DjangoのUserにひもづく。appenginepatchは、GAEでUsers APIを簡単に使えるツールを
+ragendja.authというモジュールにいくつか用意しています。
+
+* Django authの login_required の Google User版
+* Django authの AuthenticationMiddlewareの Google User版
+* Django authと Users APIをひもづくクラス (ragendja.auth.google_models)
+  - usernameや、emailは読み込み専用
+* Django authと Users APIのハイブリッドモデル (ragendja.auth.hybrid_models)
+  - usernameや、emailフィールドを変更できる。
+
+Djangoユーザを使う
+-------------------
+
+Pollでは、google_modelsを使います。目的は、ユーザがPollに投票するには、
+ログインしないといけないように修正します。そして、
+Pollに対して一回した投票できないようにします。
+
+Googleログインをさせる
+~~~~~~~~~~~~~~~~~~~~~~
+まず、投票ページにGoogleログインをさせる。投票をするときに、どのユーザを投票したかを
+保存しておくので、ログインが必要となります。
+
+ragendja.auth.decoratorsというモジュールにあるgoogle_login_requiredというデコレータを使います。
+polls/views.py を修正します。::
+
+    from ragendja.auth.decorators import google_login_required
+    ...
+
+    @google_login_required
+    def detail(request, poll_id):
+        p = get_object_or_404(Poll, id=long(poll_id))
+        return render_to_response('polls/detail.html', {'poll': p})
+    
+    @google_login_required
+    def vote(request, poll_id):
+        p = get_object_or_404(Poll, id=long(poll_id))
+        try:
+    ...
+
+これで、このviewをアクセスする時にログインしてない場合にログインをさせる。
+
+Middlewareをインストール
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+それから、どのユーザがログインしているかがとりたいので、
+GoogleAuthenticationMiddlewareをインストールします。
+
+settings.pyを修正します。::
+    
+    ...
+    MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    ...
+    'ragendja.auth.middleware.GoogleAuthenticationMiddleware',
+    ...
+    )
+    ...
+
+Googleのユーザオブジェクトも使いますので、どのUserクラスを使うかを指定します。::
+
+    ...
+    AUTH_USER_MODULE = 'ragendja.auth.google_models' 
+    ...
+
+UserVoteモデルを追加
+~~~~~~~~~~~~~~~~~~~~
+どのユーザがどのpollに投票しているのかをデータストアに保存しておきます。
+
+models.pyを修正して、UserVoteを追加します。::
+
+    ...
+    class UserVote(db.Model):
+    poll = db.ReferenceProperty(Poll)
+    choice = db.ReferenceProperty(Choice) # == parent
+    user = db.ReferenceProperty(User, verbose_name='user')
+    vote_date = db.DateTimeProperty(verbose_name='date voted',
+                                    auto_now_add=True)
+
+    def __unicode__(self):
+        return self.user.__unicode__() 
+    ...
+
+admin.pyにも追加します。::
+    
+    ...
+    from polls.models import Poll, Choice,UserVote 
+    ...
+    class UserVoteAdmin(admin.ModelAdmin):
+    fieldsets = [
+        (None,               {'fields': ['user','poll','choice']}),
+        ('Date information', {'fields': ['vote_date'], 'classes': ['collapse']}),
+    ]
+    list_display = ('user', 'poll', 'choice')
+    list_filter = ['poll']
+    ...
+    admin.site.register(UserVote, UserVoteAdmin)
+    ...
+
+投票する時にUserVoteを保存して置きます。
+
+views.pyを修正します。::
+    
+    ...
+    from polls.models import Poll, Choice, UserVote
+    from django.template import Context, loader
+    from ragendja.dbutils import get_object_or_404,db_create,transaction
+    ...
+    @google_login_required
+    def vote(request, poll_id):
+    ...
+        import logging
+        logging.debug(request.user.__class__)
+        @transaction
+        def countup_vote(key):
+            c = Choice.get(key)
+            c.votes += 1
+            c.put()
+            db_create(UserVote,
+                parent = c,
+                poll = p,
+                choice = c,
+                user = request.user,
+                non_transactional = True, # already in a transaction
+            )
+
+        countup_vote(selected_choice.key())
+    ...
+
+投票を一回しか出来ないようにする
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+投票ページを出す時に、投票してるかをチェックして、もう投票している場合に
+メッセージを出す。
+
+views.pyを修正します。::
+
+    ...
+    @google_login_required
+    def detail(request, poll_id):
+        p = get_object_or_404(Poll, id=long(poll_id))
+        voted = UserVote.all()\
+            .filter('poll =', p)\
+            .filter('user =', request.user)
+        return render_to_response('polls/detail.html', {
+            'poll': p,
+            'voted': bool(voted),
+        })
+    ...
+
+    @google_login_required
+    def vote(request, poll_id):
+        p = get_object_or_404(Poll, id=long(poll_id))
+        try:
+            voted = UserVote.all()\
+                .filter('poll =', p)\
+                .filter('user =', request.user)
+            if voted:
+                raise Exception('You have already voted')
+
+            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("You didn't select a choice.")
+        except Exception, e:
+            import logging
+            logging.info(e)
+            return render_to_response('polls/detail.html', {
+                'poll': p,
+                'error_message': e.message,
+            })
+    ...
+
+ページの表示も変わりますので、テンプレートを修正します。
+
+polls/templates/detail.html::
+
+    {% if voted %}
+    <p><strong>You have already voted.</strong></p>
+    {% else %}
+        <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>
+    {% endif %}
+
+これで、投票したユーザは一回しか投票できないようになります。

handson/settings.py

 AUTH_USER_MODULE = 'ragendja.auth.google_models'
 AUTH_ADMIN_MODULE = 'ragendja.auth.google_admin'
 # Hybrid Django/Google authentication
-AUTH_USER_MODULE = 'ragendja.auth.hybrid_models'
+AUTH_USER_MODULE = 'ragendja.auth.google_models'
 
 GLOBALTAGS = (
     'ragendja.templatetags.ragendjatags',
+{
+  "embeddedFonts" :
+[["VL-Gothic-Regular.ttf","VL-PGothic-Regular.ttf","ipam.otf","verdanaz.ttf"]],
+  "fontsAlias" : {
+    "stdFont": "VL-PGothic-Regular",
+    "stdBold": "VL-PGothic-Regular",
+    "stdItalic": "VL-PGothic-Regular",
+    "stdMono": "VL-Gothic-Regular"
+  },
+  "styles" : [
+    ["base" , {
+      "wordWrap": "None"
+    }],
+    ["literal" , {
+      "wordWrap": "None"
+    }]
+  ]
+}