Djangoが最近じわじわと国内でも注目を浴びつつあるみたいなので、ここらで自分も、解説記事を書いて、オープンソースにちょっとは協力してみようかなと。
とかいうのは建前で、ただの復習だねw
最初に、Djangoは、MVCなフレームワークではんく、MTVというスタイルを取っている。
なので、MVCなフレームワークに慣れている人からすると、ちょっとテンプレートに色々書きすぎじゃない?
という意見であるかもしれない。が、プログラマーが、テンプレートをいじらないWeb開発なんて、そうそうないでしょう?と思う。
開発環境は
openSUSE11.0
Python 2.5
Django revision 8370(Version1.0の開発バージョン)
MySQL 5.0
まず、DjangoのライブラリをPythonのPATH内に入れないといけない。
自分の場合は
svn co http://code.djangoproject.com/svn/django/trunk/ /usr/local/src/django-trunk/
sudo ln -s /usr/local/src/django-trunk/django/ [PYTHON_LIB_PATH]
といった感じになる。PYTHON_LIB_PATHの部分は環境によって違うので
python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"
を実行して調べて指定するのが通常。
これで、Djangoのインストールは完了。PHPのZendFrameworkもそうだけれど、PATHを通すだけで使えるフレームワークって最近多くていいよね。
アンインストールしたい時は、リンボリックリンクを消せばいいだけ。
次に、Djangoのコマンドを自分の環境に入れる。
ln -s /usr/local/src/django-trunk/django/bin/django-admin.py ~/bin/
これは、使いたいコマンドを一個ずつシンボリックリンク張るしかないかな。
django-admin.pyしか使わないので、今回はこれだけで。
さて、そしたら、プロジェクトを作りたい場所に移動して、早速Djangoアプリケーションを作成。
django-admin startproject [PROJECT_NAME]
と実行する。今回は、PROJECT_NAMEは integra と入れる事にする。
そうすると、プロジェクトの雛形が出来上がる。
さて、次に使うデータベースはMySQLなので、それ用の設定をする。
cd integra
vim setting.py を実行して編集。ちなみに、エディタはなんだっていいので、vimである必要性はどこにもない。
設定ファイルもPythonのコードで書かれている。一応、ReadOnlyとするために、tuple形式で書くのが通常。
今回は、MySQLを使うので、こんな感じにしてみる。
DATABASE_ENGINE = 'mysql' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'integra' # Or path to database file if using sqlite3.
DATABASE_USER = 'integra' # Not used with sqlite3.
DATABASE_PASSWORD = 'integra' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
MySQLのユーザーを設定ファイルに合わせて作成しよう。
CREATE DATABASE integra CHARACTER SET utf8;
GRANT ALL ON integra.* TO integra@localhost IDENTIFIED BY ‘integra’;
といった感じ。
自分は文字化けが嫌いなので、UTF-8を推奨するのでMySQLの設定ファイルにも以下を追加している。
default-character-set=utf8
skip-character-set-client-handshake
さて、ここまで来たら、早速、Djangoのコードを書いてみよう。
Djangoはプロジェクトの下にいくつ物アプリケーションが存在している。
ちなみに、Djangoプロジェクトで配布されているプロジェクトは、contributeという形で存在している。
なので、次にアプリケーションを作成。
python magage.py startapp task
とすると、integra/task というディレクトリが作成され、その下に初期ファイルが置かれる。
ここで忘れていけないのが、作ったアプリケーションはプロジェクトに登録しないといけない。という事だ。
vim settings.py
をして、設定ファイルを編集する。
ついでに、Djangoが持ってるアプリケーションも読み込んでおく。
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'integra.task',
)
Djangoでアプリケーション開発のベースとなるのが、Model部分なので、まず最初にmodels.pyを編集する。
何故かというと、Djangoでは、modelspy内のclassを元にデータベーステーブルを作成する仕組みになっているからだ。
RDBMSを扱うシステム開発において、データベース設計がまず最初に来るので、当然最初に作成する。
いきなり量があるけれど、まあこんな感じで作成してみる。
from django.db import models
from django.contrib import admin
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
class Attribute(models.Model):
"""
Attribute of Task.
"""
user = models.ForeignKey(User, null=False)
name = models.CharField(max_length=100, null=False)
created = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.name
class Task(models.Model):
"""
Task Model Class
Save task informations. and view it some formats.
"""
user = models.ForeignKey(User, null=False)
description = models.TextField(null=False)
start_date = models.DateTimeField(auto_now_add=True)
end_date = models.DateTimeField(null=True)
attribute = models.ManyToManyField(Attribute, verbose_name=_("Attribute"))
created = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
enabled = models.BooleanField(default=True)
def __unicode__(self):
return self.user.username + str(self.start_date) + unicode(self.attribute)
class Url(models.Model):
"""
URL Model Class.
This model have url associated with Task Model.
"""
url = models.URLField()
task = models.ForeignKey(Task)
created = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
enabled = models.BooleanField(default=True)
def __unicode__(self):
return self.url
さて、一つずつ解説していくと。
Djangoで使うModel Classを作成するには、Djangoライブラリの、django.db.models.Modelを継承する必要性がある。
更に、ユーザModelに関しては標準でDjangoが持っている django.contrib.auth.models.User Classを使う事にする。
寄って、以下のimport文が存在する。
from django.db import models
from django.contrib.auth.models import User
さて、次に、各テーブルの作成を行っている訳だが
Attribute Classから解説していこう。
Attribute Classが一つのTABLE, PropertyをCOLUMNとして捕らえる事が出来る。
データベースを操作するためのオブジェクトをプログラマーサイドで作ってしまい
それを元に、あらゆるオブジェクト、データベース設計を行うという発想なのだと思う。
user = models.ForeignKey(User, null=False)
の部分は、先ほど説明した、Djangoが標準で持っているユーザModelと外部キー接続をしている事を示す。
ここは、1:1ではなく、1:多な関係なので、models.ForeignKey Classを作成している。
第一引数には、外部キーでの接続対象となるModel名を入れる。
null=False は、キーワード引数として、オプションを設定している。
このオプションに関しては、unique=Trueなど、COLUMNの属性として指定出来る物は大抵指定できる。
詳しくは公式サイトに書いてある。
http://www.djangoproject.com/documentation/model-api/
name = models.CharField(max_length=100, null=False)
に関しては特に難しい事ないと思うが、CACHAR型のCOLUMNを作成する。
name = models.CharField(max_length=100, null=False)
は、どちらもDjangoでは同じ様に見えるが、オプションによって、MySQL内で作成されるCOLUMNが変わってくる。
createdは、MySQLのDATETIME型を作成し、アプリケーション側でRECORD作成時に一度だけ値を入れる操作を行っている。
timestampは、MySQLのTIMESTAMP型COLUMNを作成し、MySQL側でRECORDが更新される度に日付も更新している。
さて、ここで気になるのが
def __unicode__(self):
return self.user.username + str(self.start_date) + unicode(self.attribute)
の部分だが、これは、Pythonの機能を利用した表示用Methodだ。
このオブジェクトをprintなどによって表示させようとした時に、呼び出されるMethod。
元々は、__str__だったのだが、UNICODEに対応する時に、__unicode__に変わったので、最近ではこちらを採用するほうが正しい。
ただ、たまに未対応のソースコードもあるので、そういう時は、str(object)として__str__を呼び出してあげるといい。
ちなみに、__unicode__もunicode(object)で呼び出す。
更にちなみに、UNICODE文字列のリテラルはPython2.5では、u”Hello UNICODE in the Python!!”として記述する。
さて、残りのTask, Url Classに関しても同じ様な構成が続く。
ManyToMany Classが一つ見受けられるが、特にDjangoに限ったことではなく、多:多の関係なんてどこにでもあるのだし、解説は要らないと思うので割愛。
さて、これを書いただけではまだ、TABLEは作成されていない。
そこで、DjangoにModelを元にTABLEを作成してもらおう。
python manage.py syncdb
これで、一気にTABLEが作成される。
もし、どういうSQLが流されているのか確認したい場合には
python manage.py sqlall task
とすると、表示される。
こんな感じ。
BEGIN;
CREATE TABLE `task_attribute` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`user_id` integer NOT NULL,
`name` varchar(100) NOT NULL,
`created` datetime NOT NULL,
`timestamp` datetime NOT NULL
)
;
ALTER TABLE `task_attribute` ADD CONSTRAINT user_id_refs_id_4ecaf348 FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
CREATE TABLE `task_task` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`user_id` integer NOT NULL,
`description` longtext NOT NULL,
`start_date` datetime NOT NULL,
`end_date` datetime NULL,
`created` datetime NOT NULL,
`timestamp` datetime NOT NULL,
`enabled` bool NOT NULL
)
;
ALTER TABLE `task_task` ADD CONSTRAINT user_id_refs_id_19df57a0 FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
CREATE TABLE `task_url` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`url` varchar(200) NOT NULL,
`task_id` integer NOT NULL,
`created` datetime NOT NULL,
`timestamp` datetime NOT NULL,
`enabled` bool NOT NULL
)
;
ALTER TABLE `task_url` ADD CONSTRAINT task_id_refs_id_3019f8a6 FOREIGN KEY (`task_id`) REFERENCES `task_task` (`id`);
CREATE TABLE `task_task_attribute` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`task_id` integer NOT NULL,
`attribute_id` integer NOT NULL,
UNIQUE (`task_id`, `attribute_id`)
)
;
ALTER TABLE `task_task_attribute` ADD CONSTRAINT task_id_refs_id_737b532c FOREIGN KEY (`task_id`) REFERENCES `task_task` (`id`);
ALTER TABLE `task_task_attribute` ADD CONSTRAINT attribute_id_refs_id_4e1badcc FOREIGN KEY (`attribute_id`) REFERENCES `task_attribute` (`id`);
CREATE INDEX `task_attribute_user_id` ON `task_attribute` (`user_id`);
CREATE INDEX `task_task_user_id` ON `task_task` (`user_id`);
CREATE INDEX `task_url_task_id` ON `task_url` (`task_id`);
COMMIT;
さて、今回は、Modelの解説までで終わらせたいので、Viewを使わずにModelを扱う
Pythonらしいやり方を紹介。
python manage.py shell
と実行すると、対話型コマンドプロンプトへと入る事が出来る。
ここで
from django.contrib.auth.models import User
from integra.task.models import Task, Attribute, Url
とすれば、後はPythonらしく色々試す事が出来る。
例えば
>>> user = User(username="hige", password="higehige")
>>> user.save()
>>> user.id
2L
となる。
Modelオブジェクトの扱いについては次回にでも詳しく解説しようかなと思う。
ただ、Pythonのこういうところが開発効率を非常に高める部分なので、こういう事が可能だというのは、最初にお知らせしておこうかなと。
ま、正直な話、Python, Django使いに取っては当たり前の事なんだけれどね。