PythonのフレームワークDjango1.4のチュートリアル1章をやってみました

仕事で次のプロジェクトから使う言語をruby or pythonどちらにしようかという話になっています。

日本での盛り上がり方、情報量で言うとrubyだと思うのですが、pythonも海外では実績ありますし、 「やり方は1つ」という思想が継続して保守していかなければならないwebサービスに向いている感じがしました。

また、みんながやっているから自分も、という理由ではなく、自分なりに使ってみて結論を出したいところです。

ということで、pythonを勉強しつつ、ちょっとフレームワークを使って何か作ってみようということで一番メジャーっぽい Djangoを選んでチュートリアルをやってみました。

最新の1.4の1章をやってみたので残しておきます。

プロジェクト作成

$ django-admin.py startproject mysite

プロジェクトの初期構成

  • mysite/
    • manage.py <- コマンドラインツール
    • mysite/
    • \__init__.py <- pythonのパッケージでなくてはいけないもの!?
    • settings.py <- 設定ファイル
    • urls.py <- ルーティング定義
    • wsgi.py <- WSGIに準拠したウェブサーバを使う時のエンドポイント

開発用サーバ起動

$ python manage.py runserver
  • 8000番ポートでアクセス可能

使うポートを変える場合、

$ python manage.py runserver 8080

のようにすることで、8080番ポートでアクセス可能になる

DBのセットアップ

mysite/settings.py

DATABASES = {
    'default': {
        'ENGINE': '', # postgreSQL, mysql, sqlite3, oracle等々設定可能
        'NAME': '{sqliteファイルへのパス}'
        # sqlite3を使用する場合は、その他の設定は必要なし
    }
}

TimeZoneの設定

ここを参考に、

mysite/settings.py を変更

TIME_ZONE = 'America/Chicago'
↓
TIME_ZONE = 'Asia/Tokyo Japan'

※ これだとrunserverした時にエラーになった。。

TIME_ZONE = 'Asia/Tokyo'

が正解のようです。

INSTALLED_APPS

使用するモジュールの一覧!?

db作成

$ python manage.py syncdb

すると、ずらずらメッセージが出てくるので質問に答えていく。

Creating tables ...
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_user_permissions
Creating table auth_user_groups
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table django_site

You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'ojimac'): {Enter}
E-mail address: {メールアドレス}
Password: {パスワード}
Password (again): {パスワード}
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

全部終わると、tableがもろもろ(auth_とかdjango_というテーブル名)出来ている。

モデルの作成

  • プロジェクトの中に複数アプリを作ることができる!?

ex) pollsアプリの作成

$ python manage.py startapp polls

polls/models.py を編集

from django.db import models

class Poll(models.Model): # django.db.models.Modelのサブクラスとしてモデルを定義する
    # フィールド名をモデルクラスにセットしていく
    poll   = models.ForeignKey(Poll)
    choice = models.CharField(max_length = 200)
    votes  = models.IntegerField()

モデルのアクティベーション

settings.py

INSTALLED_APPS = (
    'django.contrib.auth',
    ・
    ・
    ・
    'polls', # 追加する
)

djangoの思想として、プラガブルなこと。ここでつくったアプリは、他のプロジェクトでも使えるようにしているみたいです。

$ python manage.py sql polls

で、polls_poll, polls_choiceテーブルのCREATE文が発行される。

djangoの思想として、ちゃんとsqlを明示することが必要と考えているからこのようなコマンドを用意しているみたいです。

その後、

$ python manage.py syncdb

をすることで、polls_poll, polls_choiceテーブルが自動生成される。

APIを動かしてみる

$ python manage.py shell

で、python shellを立ち上げます。

>>> from polls.models import Poll, Choice # Poll, Choiceモデルを使えるようにする
>>> Poll.objects.all() # polls_pollテーブルを全件取得
[] # まだ何もデータがないので空が返ってきます

# レコードを追加してみます
# 時間を扱えるモジュールをインポート
>>> from django.utils import timezone
# questionカラムに"What's new?"を、pub_dateに現在時刻をセット
>>> p = Poll(question="What's new?", pub_date=timezone.now())
# insert
>>> p.save()
# この時点でIDは1
>>> p.id
1
# id=1のquestionカラム値
>>> p.question
"What's new?"
# id=1のpub_dateカラム値
>>> p.pub_date
datetime.datetime(2012, 5, 29, 0, 35, 25, 9851, tzinfo=)
# updateしてみる
>>> p.question = "What's up?"
>>> p.save()

Poll.objects.all()したときの出力

  <Poll: Poll object>

が見づらいので、

polls/models.pyに unicode メソッドを足します。

class Poll(models.Model):

    // snip
    
    def __unicode__(self):
        return self.question
        
class Choice(models.Model):

    // snip
    
    def __unicode__(self):
        return self.choice

すると、Poll.objects.all()の出力は、

Poll.objects.all()

    <Poll: What's up?>

のように見やすくなりました。

時間に関する便利関数を追加してみます。

import datetime
from django.utils import timezone
// snip

class Poll(models.Model):

    // snip

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

python shellから実行して結果を確認します。

$ python manage.py shell
>>> from polls.models import Poll, Choice
>>> Poll.objects.all()

# polls_poll.id = 1のレコードのみ取得
>>> Poll.objects.filter(id=1)

# questionカラムがWhatではじまるレコード取得
>>> Poll.objects.filter(question__startswith='What')

# pub_dateカラムが2012
>>> Poll.objects.get(pub_date__year=2012)

# id=2のレコードはないのでエラーになる
>>> Poll.objects.get(id=2)

# Poll.objects.get(id=1)と等価
>>> Poll.objects.get(pk=1)

# Pollモデルに実装したカスタムメソッドも動きます
>>> p.was_published_recently()

# 関連のあるデータのinsert
>>> p = Poll.objects.get(pk=1)
>>> p.choice_set.all()
# poll_id = 1のレコード追加
>>> p.choice_set.create(choice='Not much', votes=0)
# poll_id = 1のレコードもう1件追加
>>> p.choice_set.create(choice='The sky', votes=0)
# poll_id = 1のレコードもう1件追加
>>> c = p.choice_set.create(choice='Just hacking again', votes=0)

# cオブジェクトに関連のある(poll_id=1)のpolls_pollテーブルの値を抽出
>>> c.poll

# 関連のあるデータ取得
>>> p.choice_set.all()

# count(*)する
>>> p.choice_set.count()

# 関連のあるモデルのプロパティを条件にするには、
__(アンダースコア前後2つ)__
で取得可
>>> Choice.objects.filter(poll__pub_date__year=2012)

# deleteする場合
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()

以上です。 2章に続きます。