Django Applicationを作る

ちょっと意味のあるアプリケーションとして、TODO管理機能を作っていくことにします。

Djangoと同じく、以下のコマンドでアプリケーションが生成されます。

manage.py startapp todo

これによりtodoフォルダができますので、中身を確認すると、以下のファイル・フォルダ群ができています。

media/
models.py
templates/
views.py
__init__.py

まず、Todo情報を表すモデルクラスを作成します。先ほど生成されたmodels.pyファイルに、以下のコードを加えました。

/todo/models.py

from google.appengine.ext import db
from django.contrib.auth.models import User

class Task(db.Model):
    user = db.ReferenceProperty(User)
    title = db.StringProperty()
    create_time = db.DateTimeProperty(auto_now_add=True)
    limit_time = db.DateTimeProperty()

次に、このTodo情報を閲覧するメソッドを用意します。先ほど生成されたviews.pyファイルに、以下のコードを加えました。

/todo/views.py

from django.views.generic.list_detail import object_list
from ragendja.template import render_to_response
from todo.models import Task

def list_tasks(request):
    if not request.user.is_authenticated():
        return render_to_response(request, "login.html")

    queryset = Task.all().filter("user", request.user)
    return object_list(request, queryset, paginate_by=20)

ここでは、DjangoのGeneric View(汎用ビュー)を利用することにしました。これに対応する一覧表示画面のテンプレートを用意します。汎用ビューの命名規則に沿った名前(この場合はtask_list.html)にしておけば、views.pyでテンプレート名を指定する必要はありません。

/todo/templates/task_list.html

{% extends "base.html" %}

{% block head_title %}TODOリスト{% endblock %}
{% block body_main %}
<table>
  <tr><th>タイトル</th><th>締切</th></tr>
  {% for task in object_list %}
  <tr><td>{{ task.title }}</td><td>{{ task.limit_time|date:"Y-m-d" }}</td></tr>
  {% endfor %}
</table>
  
<div>
  {% if has_previous %}
    <a href="{% url todo.views.list_tasks %}?page={{ previous }}">前へ</a>
  {% endif %}
  {% if has_next %}
    <a href="{% url todo.views.list_tasks %}?page={{ next }}">次へ</a>
  {% endif %}
</div>

{% endblock %}

ページ下部の{% if has_previous %}...で始まる個所は、ページング処理を記述しています。

最後に、todoフォルダ内にurls.pyを用意し、トップのurls.pyから呼び出されるようにします。また、setting.pyでtodoアプリケーションに関して追記します。

/todo/urls.py

# -*- coding: utf-8 -*-
from django.conf.urls.defaults import *
from ragendja.urlsauto import urlpatterns

urlpatterns = patterns('todo.views',
    (r'^$', 'list_tasks'),
)

/urls.py

urlpatterns = patterns('',
    (r'^$', 'topapp.views.welcome'),
    (r'^todo/', include('todo.urls')),

/settings.py

INSTALLED_APPS = (
...中略...
    'todo',
)

これで、Todo一覧のページができました。

同じ要領で、Todoタスクの追加ページを作ることにします。まず、Todoタスク追加フォームを表すModelFormクラスを作成します。todoフォルダ内に、新たにforms.pyファイルを作って、以下の内容を記述しました。

/todo/forms.py

from django import forms
from todo.models import Task

class TaskForm(forms.ModelForm):
    user = forms.CharField(widget=forms.HiddenInput, required=False)
    title = forms.CharField(max_length=100, required=True, label=u"タイトル", help_text=u"(必須)")
    limit_time = forms.DateTimeField(required=False, label=u"締切", help_text=u"(任意)yyyy-mm-ddの形式で入力してください")
    class Meta:
        model = Task
        exclude = ('create_time')

create_timeは自動生成されるものを利用するので、excludeに指定してユーザからの入力対象外としました。また、userにはログインユーザを登録する予定なので非表示(hidden)の入力フォームとしました。

次に、Todoタスク追加フォームを処理するメソッドをviews.pyに記述します。

/todo/views.py

from django.core.urlresolvers import reverse
from django.views.generic.create_update import create_object

def add_task(request):
    if not request.user.is_authenticated():
        return render_to_response(request, "login.html")
    
    request.POST = request.POST.copy()
    request.POST["user"] = str(request.user.key())
    return create_object(request, form_class=TaskForm,
                         post_save_redirect=reverse('todo.views.list_tasks'))

ここでも、汎用ビューを利用しています。続いて、汎用ビューの命名規則に沿った追加フォームを作ります。

/todo/templates/task_form.html

{% extends "base.html" %}

{% block head_title %}TODO追加{% endblock %}
{% block body_main %}
<form action="" method="post">
    <table>
        {{ form.as_table }}
        <tr><td colspan="2">
        <input type="submit" value="{% if object %}編集{% else %}追加{% endif %}" />
        </td></tr>
    </table>
</form>

<a href="{% url todo.views.list_tasks %}">一覧へ戻る</a>
{% endblock %}

最後に、urls.pyに以下の記述を追加して完了です。

/todo/urls.py

urlpatterns = patterns('todo.views',
    (r'^$', 'list_tasks'),
    (r'^create$', 'add_task'),

manage.py runserverコマンドで開発サーバを立ち上げて確認し、manage.py updateでアップロードしました。

このままだとTODOタスクは増えていく一方なので、次から、TODOタスクの編集と削除処理を作っていこうと思います。