Django基本チュートリアル2 掲示板を作る1
February 07, 2009 at 11:01 AM | View Commentsの続きです。
次に簡単な掲示板を作ってみます。
アプリの名前はbbsとします。
firstprojectのディレクトリに移動して
% python manage.py startapp bbs
でアプリを作ります。
startproject/settings.py のINSTALLED_APPSに firstproject.bbsを追加します。
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'firstproject.firstapp',
'firstproject.bbs', #追加
)
次にモデルを作ります、。
firstproject/bbs/models.py
from django.db import models
class Entry(models.Model):
author = models.CharField(max_length=50)
body = models.TextField()
updated = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.author
authorが投稿者、bodyが掲示板に書き込みをした内容、updatedは投稿、編集した時刻です。
updatedのauto_now=Trueは、何もしなくても新規や変更のあったときに時刻を記録してくれるタイムスタンプです。
__unicode__はこのモデルのインスタンスを表示するときに返す文字列です。ここではauthorを返すようにしました。
次にmodelsをデータベースに反映させます。
はじめてsyncdbをする場合はINSTALLED_APPSに登録しているアプリのモデルすべてを反映します。
% python manage.py syncdb
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
# bbsアプリのEntryモデルを作る
Creating table bbs_entry
# スーパーユーザーを作るか聞かれます。username admin password adminで作っておきましょう。後で修正できます。
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: admin
E-mail address: #あなたのメールアドレス
Password: #admin
Password (again): #admin
Superuser created successfully.
Installing index for auth.Permission model
Installing index for auth.Message model
これでbbs_entryというテーブルが出来ました。
では、どんなSQLでテーブルが作られたか見てみましょう。
% python manage.py sql bbs
BEGIN;
CREATE TABLE "bbs_entry" (
"id" integer NOT NULL PRIMARY KEY,
"author" varchar(50) NOT NULL,
"body" text NOT NULL,
"updated" datetime NOT NULL
)
;
COMMIT;
id は自動で振られる値でPRIMARY KEYになります。
Djangoは manage.py shellでPyhonの対話式でアプリを試すモードがあるので、これをつかって今つくったモデルを扱ってみましょう。
% python manage.py shell
Python 2.5.4 (r254:67916, Dec 23 2008, 15:10:54) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
# bbs/models.pyのEntryクラスをインポート
>>> from bbs.models import Entry
# id と updatedは自動で入るのでauthorとbodyのみ引数にしてEntryクラスのインスタンスを作ります。
>>> e = Entry(author="John", body="first entry")
#どんな値があるのか見てみましょう。idとupdatedの値はまだなく、データベースにも反映されてません。
>>> e.__dict__
{'body': 'first entry', 'updated': None, 'id': None, 'author': 'John'}
#saveメソッドを呼び出すことでデータベースに反映されます。
>>> e.save()
>>> e.__dict__
{'body': 'first entry', 'updated': datetime.datetime(2009, 2, 6, 20, 20, 30, 562000), 'id': 1, 'author': 'John'}
# 次にデータベースからすべてのデータを取得してみましょう
>>> entrys = Entry.objects.all()
>>> entrys
[<Entry: John>]
# id(primarykey)が1のもの(先ほど作ったデータ)を取得
>>> e1 = Entry.objects.get(pk=1)
>>> e1.__dict__
{'body': u'first entry', 'updated': datetime.datetime(2009, 2, 6, 20, 20, 30, 562000), 'id': 1, 'author': u'John'}
# id,author,body,updateなどは属性になっています。
>>> e1.body
u'first entry'
>>> e1.updated
datetime.datetime(2009, 2, 6, 20, 20, 30, 562000)
# インスタンスのdeleteメソッドでデータが消えます。
>>> e1.delete()
# 消えたか確認
>>> Entry.objects.all()
[]
>>> Entry.objects.count()
0
#テスト用にデータを作っておく
>>> e = Entry(author="John", body="body1")
>>> e.save()
>>> e = Entry(author="Paul", body="body2")
>>> e.save()
>>> Entry.objects.all()
[<Entry: John>, <Entry: Paul>]
と、このようにデータを扱うことができます。
より詳しくモデルの扱いを知りたい場合はドキュメントを参考にしましょう。
クエリを生成する — Django v1.0 documentation
では、今つくったエントリーを実際にブラウザで表示してみましょう。
URLの振り分けはfirstproject/urls.py 表示する部分を作るのはfirstproject/bbs/views.py、
になります
firstproject/urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^$', 'firstproject.firstapp.views.helloworld', name='home'),
(r'^ut/$', 'firstproject.firstapp.views.usetemplate'),
(r'^plus/(?P<arg1>\d+)/(?P<arg2>\d+)/$', 'firstproject.firstapp.views.calc',
{"templatename": "calc.html"}),
(r'^bbs/$', 'firstproject.bbs.views.object_list'), #これを追加
)
firstproject/bbs/views.py
from django.shortcuts import render_to_response
from bbs.models import Entry
def object_list(request):
object_list = Entry.objects.all()
return render_to_response("object_list.html",
{
"object_list": object_list,
}
)
テンプレートにobject_list.htmlというファイルを使うように指定したので作ってみましょう。
アプリ直下にtemplatesというディレクトリを作るとDjangoは自動的にtemplatesを探してくれます。
% mkdir bbs/tempates
そしてobject_list.htmlというファイルを作ります。
firstproject/bbs/templates/object_list.html
{% for object in object_list %}
<dl>
<dt>{{ object.id }} :<font color=green><b>{{ object.author }}</b>◆</font>
:{{ object.updated|date:"Y-m-d H:i" }}</dt>
<dd>{{ object.body }}</dd>
</dl>
{% endfor %}
これで
のようなものが表示されたと思います。|date:"Y-m-d H:i"はテンプレートタグのフィルターと呼ばれるものです。ここではdatetimeの表示を見やすくしました。
フィルターは他にもいろいろあるのでドキュメントを調べてみてください。
組み込みタグ/フィルタリファレンス — Django v1.0 documentation
さて、表示の部分はできましたが、掲示板なのでユーザーの投稿のフォームが必要です。
Djangoにはモデルから簡単にフォームを作る機能があるのでそれを利用しましょう。
一度、サーバーをとめて、再び対話式を使って実験してみます。
% python manage.py shell
# forms と bbs/models.pyのEntryをインポート
>>> from django import forms
>>> from bbs.models import Entry
# Entryモデルに基づいたEntryFormクラスを作ります。
>>> class EntryForm(forms.ModelForm):
... class Meta:
... model = Entry
...
# インスタンス化
>>> f = EntryForm()
# print で htmlが表示されます。
>>> print f
<tr><th><label for="id_author">Author:</label></th><td><input id="id_author" type="text" name="author" maxlength="50" /></td></tr>
<tr><th><label for="id_body">Body:</label></th><td><textarea id="id_body" rows="10" cols="40" name="body"></textarea></td></tr>
# as_pメソッドでpタグくくりにもできます。
>>> print f.as_p()
<p><label for="id_author">Author:</label> <input id="id_author" type="text" name="author" maxlength="50" /></p>
<p><label for="id_body">Body:</label> <textarea id="id_body" rows="10" cols="40" name="body"></textarea></p>
# authorやbodyなど一部のhtmlを表示させたいときは辞書のように指定します。
>>> print f["author"]
<input id="id_author" type="text" name="author" maxlength="50" />
# ユーザーからのデータ入力は辞書で値を渡します
>>> f = EntryForm({"author":"Link"})
# authorだけでbodyを入力しませんでした。そうするとerrorsにエラーメッセージが辞書で渡されます。
>>> f.errors
{'body': [u'This field is required.']}
# is_validメソッドは正しいデータがあるか確認するメソッド
>>> f.is_valid()
False
# 今度はauthorもbodyも入力
>>> f = EntryForm({"author":"Link", "body":"new entry"})
# errorsは空で、is_validメソッドはTrueを返します
>>> f.errors
{}
>>> f.is_valid()
True
# フォームインスタンスをsaveすることでデータベースに反映することもできます
>>> f.save()
<Entry: Link>
>>> Entry.objects.all()
[<Entry: John>, <Entry: Paul>, <Entry: Link>]
>>>
では、上の結果をふまえてフォーム部分を作ります。
まず、firstproject/bbs/forms.pyというファイルを作ってEntryFormクラスを書きましょう。
from django import forms
from bbs.models import Entry
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
次にformを表示させるためにfirstproject/bbs/views.pyを編集します。
from django.shortcuts import render_to_response
from bbs.models import Entry
from bbs.forms import EntryForm
def object_list(request):
if request.method == "POST": #requestがPOSTかGETか判別
form = EntryForm(request.POST) #request.POSTは辞書のようなデータなのでそのままEntryFormに渡せる
if form.is_valid(): # エラーがないか判別
form.save() #エラーがないのでsave()
form = EntryForm() #保存したのでフォームを空に、is_valid()でFalseの場合はerrosや入れられた値を持ったまま
else:
form = EntryForm() #GETなので空のフォームを作る
object_list = Entry.objects.all()
# formとobject_listをテンプレートに渡す
return render_to_response("object_list.html",
{
"form": form,
"object_list": object_list,
}
)
慣れないと複雑に見えるかもしれませんが、すぐになれると思います。
次にテンプレートにフォームの部分を追加します。
firstproject/bbs/templates/object_list.html
{% for object in object_list %}
<dl>
<dt>{{ object.id }} :<font color=green><b>{{ object.author }}</b>◆</font>
:{{ object.updated|date:"Y-m-d H:i" }}</dt>
<dd>{{ object.body }}</dd>
</dl>
{% endfor %}
<form method="POST" action="." >
<table>
{{ form }}
</table>
<input type="submit" />
</form>
これで非常に簡単ですが掲示板ができました。
authorとbodyどちらかしか入力しないでsubmitボタンを押すと、エラーメッセージがでると思います。