Goolge app engine + Djangoで汎用ビュー(object_list)を扱う方法

  • 4月 11, 2008 08:24

Djangoには汎用ビューという便利な機能があって、

http://michilu.com/django/doc-ja/generic_views/

特にpaginateを簡単に扱えるdjango.views.generic.list_detail.object_listは非常に便利なのですが

http://michilu.com/django/doc-ja/generic_views/#django-views-generic-list-detail-object-list

Google Apps Engineでは扱うことができない。

しかし、ちょっといじればいけそうなのでやってみました。

まずREQUEST_CONTEXTを使っていて、デフォルトではdjangoのmodelに依存しているdjango.contrib.authを使っているのでsettings.pyに以下を追加してで設定を上書きする。

TEMPLATE_CONTEXT_PROCESSORS = (
   #'django.core.context_processors.auth',
   'django.core.context_processors.debug',
   'django.core.context_processors.i18n',
   #'django.core.context_processors.media', #mediaは0.97からかな?0.96にはないはず
   'django.core.context_processors.request',
)

object_list関数のなかに

queryset = queryset._clone()

というのがあって、それのためにエラーになるので

setattr(query, '_clone', lambda : query)

を追加。

object_listの引数にtemplate_nameがないとqueryset.modelを見てエラーになるので必ず引数として渡す。

この前の例だと以下のようになる(userの部分が間違ってたので`Djangoを動かした。 - 偏った言語信者の垂れ流し`_ を参考に直しました。)

#!-*- coding:utf-8 -*-
from django.http import HttpResponse
from django.views.generic.list_detail import object_list
from django.shortcuts import render_to_response
from django import newforms as forms

from google.appengine.ext import db
from google.appengine.api import users
import datetime

class Entry(db.Model):
    created = db.DateTimeProperty()
    body = db.StringProperty(required=True)
    author = db.UserProperty()

class EntryForm(forms.Form):
    body = forms.CharField(max_length=100, min_length=1)

def bbs_list(request):
    form = EntryForm(request.POST or None)
    user = users.get_current_user()
    if user:
        userlink = "%s (<a href='%s'>sign out</a>)" % (user.nickname(), users.create_logout_url("/hoge/list/"))
    else:
        userlink = "<a href='%s'>Sign in or register</a>." %  (users.create_login_url("/hoge/list/"))
    if form.is_valid():
        e = Entry(body=unicode(request.POST["body"], 'utf8'),
            created=datetime.datetime.now(),
            )
        if user:
            e.author = user
        e.put()
        form = EntryForm()
    query = Entry.all()
    query.order('-created')
    setattr(query, '_clone', lambda :query) #この行を追加
    #return render_to_response('hoge/entry_list.html', {'form':form, 'object_list':query, 'nickname':nickname})
    return object_list(request, query, paginate_by=10,
            template_name='hoge/entry_list.html', #template_nameを必ず渡す
            extra_context={'form': form, 'userlink':userlink}
            )

テンプレートは次のようになる

ueblog33/hoge/templates/hoge/entry_list.html

{% extends "base.html" %}
{% block title %}HOGE{% endblock %}
{% block content %}
<ul>
<p>
  <form method="POST" action="." >
      {{ form }}
   <input type="submit" />
   </form>
</p>
<p>
{{ userlink }}
</p>
{% for object in object_list %}
<li>{{ object.body|escape }} : {{ object.created|date:"Y-m-d (D) H:i:s" }} : {% if object.author %}{{ object.author }}{% else %}名無しさん{% endif %}</li>
{% endfor %}
</ul>
{% if has_previous %}
  <a href="/hoge/list/?page={{ previous }}">previous</a>
{% endif %}
{% if has_next %}
  <a href="/hoge/list/?page={{ next }}">next</a>
{% endif %}
{% endblock %}

他の汎用ビューはdate_basedだけが惜しいのですが、ちょっとやれば使えそうなので次回にでもやってみたいと思います。というかdjango.modelをうまくgoogleのdb.Modelに対応するのを作ってる人がいるみたいなのでそっちに期待。

上記のアプリは以下で動いてます

http://ueblog33.appspot.com/hoge/list/