django の評価 (2)

再開。参考にしているのは Python Webフレームワーク、第1回: DjangoとPythonを使ってWeb開発を行う という文書。

ビューの実装

まず、jobs\views.py を以下のように修正

from django.template import Context, loader
from django.http import HttpResponse
from jobs.models import Job

def index(request):
    object_list = Job.objects.order_by('-pub_date')[:10]
    t = loader.get_template('jobs/job_list.html')
    c = Context({
        'object_list': object_list,
    })
    return HttpResponse(t.render(c))

これ、テンプレートが無いと意味分かりませんな。資料にある v3 は一旦スルーして、次の節へ

テンプレート作成

まず、どこにテンプレートを置くか、な記述が必要 (置き場所の作成も)。settings.py に以下の記述を追加してディレクトリを掘る

TEMPLATE_DIRS = (
    'd:/django/djproject/templates/',
)

テンプレートは継承可能との事にて、スケルトンを作成している。templates/base.html を作成し、以下の記述を追加

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Company Site: {% block title %}Page{% endblock %}</title>
    {% block extrahead %}{% endblock %}
  </head>
  <body>
    {% block content %}{% endblock %}
  </body>
</html>

あるいはアプリケーションのスケルトンとして以下 (templates/jobs/base.html)

{% extends "base.html" %}

{% block extrahead %}
    <style>
        body {
            font-style: arial;
        }
        h1 {
            text-align: center;
        }
        .job .title {
            font-size: 120%;
            font-weight: bold;
        }
        .job .posted {
            font-style: italic;
        }
    </style>
{% endblock %}

これはスタイルシートのみ。次が v2 なビュー (上にて記述) からロードされるテンプレートになる。(templates/jobs/job_list.html)

{% extends "jobs/base.html" %}

{% block title %}Job List{% endblock %}

{% block content %}
    <h1>Job List</h1>
    <ul>
    {% for job in object_list %}
        <li><a href="{{ job.id }}">{{ job.job_title }}</a></li>
    {% endfor %}
    </ul>
{% endblock %}

extends が継承するナニを指定している、と類推。あるいは object_list というシンボルはビューで記述されているソレと類推。
とりあえず、これで一覧表示な準備は整ったはず。

d:\django\djproject>python manage.py runserver
(出力略

で、ブラウザで http://localhost:8000/jobs にアクセス。実はテンプレートのファイル名を jobs_list.html にしてて叱られております。修正後、一応正常に表示できてますが、レコードが皆無なので出力されるのは Job List というタイトルのみ。
仕方が無いので jobs\models.py に Admin なインナークラスの定義を追加して、上書き後に速攻リロードしたらコンテンツ表示できず。サーバ側で準備ができてなかった模様。処理の終了を確認後、再試行したら Jobs も表示。

ちょっと寄り道

CRUD な管理インターフェースをいちいち作る手間がいらん、という話でしたが、Add job な画面を見るに、日付は選択できるわ Location は追加できるわでびっくり仰天。ヘッダーにはパンくずリストやらその他モロモロなリンクもある。
job テーブルに一件追加して上記コンテンツを見ると、一件追加されていたが、詳細画面なソレをまだ作成していない。

detail

まず、view を以下のように修正

from django.shortcuts import get_object_or_404, render_to_response
from jobs.models import Job

def index(request):
    object_list = Job.objects.order_by('-pub_date')[:10]
    return render_to_response('jobs/job_list.html',
                              {'object_list': object_list})

def detail(request, object_id):
    job = get_object_or_404(Job, pk=object_id)
    return render_to_response('jobs/job_detail.html',
                              {'object': job})

上記によれば jobs/job_detail.html が必要なんですね。以下を追加。

{% extends "jobs/base.html" %}

{% block title %}Job Detail{% endblock %}

{% block content %}
    <h1>Job Detail</h1>

    <div class="job">
        <div class="title">
            {{ job.job_title }}
            -
            {{ job.location }}
        </div>
        <div class="posted">
            Posted: {{ job.pub_date|date:"d-M-Y" }}
        </div>
        <div class="description">
            {{ job.job_description }}
        </div>
    </div>
{% endblock %}

で、試験。detail が出ない。リンクを見ると http://localhost:8000/jobs/1 とかになってるし、テーブル的にも 1 という id はあるように見える。むむむ、と言いつつ jobs/views.py を以下に修正したら出た。(を

def detail(request, object_id):
    job = get_object_or_404(Job, pk=object_id)
    return render_to_response('jobs/job_detail.html',
                              {'job': job})

いくつか気になる点

  • 既存の rails アプリと DB を共有したい (特に認証部分)
    • rails も確かテーブル名をデフォルトではないソレにできたはずですが、django も同様な模様 (http://ymasuda.jp/python/django/docs/model-api.html#id18)。
    • フィールドも差異があるけど、rails な login_engine と共存できるのかなぁ。余計なフィールドがあってもお構いなし、なソレだったら助かるんですが。
  • syncdb は列の add なんかにも対応できるのかどうか
    これはやってみないと分からんな。
  • 国際化
  • 試験
  • 静的コンテンツの取り扱い

もう少しチュートリアル等を試験しながら色々確認予定。

テーブルの名前

モデルの中でインナークラスをナニすれば良い、との事。以下のような定義を追加してみた。

class Test(models.Model):
    city = models.CharField(maxlength=50)
    state = models.CharField(maxlength=50, null=True, blank=True)
    country = models.CharField(maxlength=50)

    def __str__(self):
        if self.state:
	    return "%s, %s, %s" % (self.city, self.state, self.country)
        else:
	    return "%s, %s" % (self.city, self.country)

    class Meta:
        db_table = 'xxxx'

で syncdb して sqlite3 な .tables を確認

d:\django\djproject>python manage.py syncdb
Creating table xxxx
Adding permission 'test | Can add test'
Adding permission 'test | Can change test'
Adding permission 'test | Can delete test'

d:\django\djproject>..\sqlite-3_3_17\sqlite3 djproject.db
SQLite version 3.3.17
Enter ".help" for instructions
sqlite> .table
auth_group                 django_admin_log
auth_group_permissions     django_content_type
auth_message               django_session
auth_permission            django_site
auth_user                  jobs_job
auth_user_groups           jobs_location
auth_user_user_permissions xxxx
sqlite>

名前的には良いんですが、django な認証テーブルなソレはもう少し検証が必要。ruby みたいにクラスのオーバーライドみたいな真似ができればシアワセなんですが。

認証

rails の login_engine なソレでの認証も可能に見えるな。AUTHENTICATION_BACKEND に自作の認証バックエンドなクラスを追加しておけば良さげ。あとは login_engine なテーブルにアクセスするだけなのかなぁ。

http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py を確認せねば、なソレですか。