ServersMan@VPS Django で掲示板を作る


前回(ServersMan@VPS Python 2.7 + Django 1.2.3 のインストール)からの続きです。
Django で簡単な掲示板を作ってみます。

  • Django 1.2.3
  • Python 2.7
  • データベースはSQLite3


目次

1. Django の置き場を決める

どこでもいいです。今回は、/var/www/django に作ってみます。

mkdir /var/www/django
cd /var/www/django

2. プロジェクトを作る

アプリのホームになります。アプリ名は、Python のモジュールと重複しないこと、ハイフンを使わなければ何でもいいです。

django-admin.py startproject アプリ名

※ 今回は、vpstest で作りました。

3. 開発用サーバの起動

Django には開発用の簡易 httpd が付属してるので、そやつを起動してみます。

cd vpstest
python manage.py runserver VPSのIPアドレス:8000
Validating models...
0 errors found

Django version 1.2.3, using settings 'vpstest.settings'
Development server is running at http://VPSのIPアドレス:8000/
Quit the server with CONTROL-C.

エラーがなければ開発用 httpd が起動してるはずです。ブラウザでアクセスしてみます。

http://VPSのIPアドレス:8000

こんな画面が出てれば成功。

※ Ctrl + C で開発用 httpd を落とせます。

4. データベース、タイムゾーン、言語の設定

アプリ名ディレクトリ内に、settings.py ファイルが作成されているので、編集します。

vi settings.py
# 一番上に追記↓
import os

# ENGINE、NAME を編集
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.realpath(os.path.dirname(__file__)) + os.sep + 'db.sqlite3',
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
    }
}

TIME_ZONE = 'Asia/Tokyo'
LANGUAGE_CODE = 'ja'

5. データベースの反映

管理者用のID、パスワードも聞かれます。適当に入力してメモっておいてください。

python manage.py syncdb
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 auth_message
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 'root'): 管理者用ID(省略時は root)
E-mail address: メールアドレス
Password: パスワード
Password (again): 上で入力したパスワード
Superuser created successfully.
Installing index for auth.Permission model
Installing index for auth.Group_permissions model
Installing index for auth.User_user_permissions model
Installing index for auth.User_groups model
Installing index for auth.Message model
No fixtures found.

6. データベースの確認

syncdb の結果、各種テーブルが作成されているか確認します。

python manage.py dbshell
SQLite version 3.7.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"

# データベースの確認
sqlite> .databases
seq  name             file                                                      
---  ---------------  ----------------------------------------------------------
0    main             /var/www/django/vpstest/db.sqlite3                        
1    temp    

# テーブルの確認
sqlite> .table
auth_group                  auth_user_groups          
auth_group_permissions      auth_user_user_permissions
auth_message                django_content_type       
auth_permission             django_session            
auth_user                   django_site

# sqlite から切断
sqlite> .quit

7. アプリケーションの作成

掲示板(bb)を作ります。

python manage.py startapp bb
ls bb
__init__.py  models.py  tests.py  views.py

自動で4ファイル作成されています。

8. モデルの定義

掲示板の構成要素を検討します。

  • タイトル
  • 名前
  • 投稿日時
  • 本文

最低限必要な要素は、こんなところでしょうか。では、この要素をモデルとして定義してみます。

vi bb/models.py
from django.db import models
from django.contrib import admin

# Create your models here.
class BB(models.Model):
    title  = models.CharField(max_length=100)
    name = models.CharField(max_length=100)
    post_date = models.DateTimeField(auto_now_add=True)
    comment = models.TextField()

    def __unicode__(self):
        return self.title + '(' + self.name + ')'
        
admin.site.register(BB)

ちょっと解説します。

  • def __unicode__ でリターンする文字列は、Django が Object を表現するときに出力する文字列を指定できます。
  • CharField、DateTimeField、TextField は、django.db.models.fields モジュールで定義されていて、django.db.models 内でインポートされています。
  • admin.site.register は、指定したモデルを後述する管理画面で管理できるようにします

CharField

  • 文字列のフィールドを意味します。
  • 短めの文字列で最適
  • 必須の引数で max_length
  • max_length=100 は、最大文字数が100文字までを意味します。この指定は、Djangoのバリデーション、DB制約として適用されます。

DateTimeField

  • 日付と時刻のフィールドを意味します。
  • 引数は、auto_now、auto_now_add

TextField

  • 文字列のフィールド
  • 長めの文字列で最適

django.db.models.fields の詳しい仕様はこちら
http://djangoproject.jp/doc/ja/1.0/ref/models/fields.html

9. モデルの反映

モデルを定義したので、アプリケーションを追加します。同時に管理サイトを有効にしておきます。

vi settings.py
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.admin',
    'vpstest.bb',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
)

データベースにアプリケーション(bb)のモデル定義を反映します。
まずはSQL確認

python manage.py sql bb
BEGIN;CREATE TABLE "bb_bb" (
    "id" integer NOT NULL PRIMARY KEY,
    "title" varchar(100) NOT NULL,
    "name" varchar(100) NOT NULL,
    "post_date" datetime NOT NULL,
    "comment" text NOT NULL
)
;COMMIT;

続いて、データベースに反映

python manage.py syncdb
Creating table django_admin_log
Installing index for admin.LogEntry model
No fixtures found.

確認してみます。

python manage.py dbshell
SQLite version 3.7.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .schema bb_bb
CREATE TABLE "bb_bb" (
    "id" integer NOT NULL PRIMARY KEY,
    "title" varchar(100) NOT NULL,
    "name" varchar(100) NOT NULL,
    "post_date" datetime NOT NULL,
    "comment" text NOT NULL
);
sqlite> .quit

※ モデルに未指定の id カラムが PK として自動生成されてます。

10. 管理サイトの有効化

URLをマッピングします。

vi urls.py
from django.conf.urls.defaults import *

# Uncomment the next two lines to enable the admin:
from django.contrib import admin  ←コメントアウト解除
admin.autodiscover()  ←コメントアウト解除

urlpatterns = patterns('',
    # Example:
    # (r'^vpstest/', include('vpstest.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # (r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    (r'^admin/', include(admin.site.urls)),  ←コメントアウト解除
)

管理サイトを確認してみます。まず開発用httpd の起動

python manage.py runserver VPSのIPアドレス:8000

ブラウザで管理サイトへアクセス

http://VPSのIPアドレス:8000/admin/

・ユーザ名:5の手順でメモっていた管理者用のID
・パスワード:5の手順でメモっていた管理者用パスワード
・ログイン

管理サイトにログインできたら、「追加」をクリック

・Title:適当に入力
・Name:適当に入力
・Comment:適当に(ry
・保存

※ post_date がないのは、モデル定義で、auto_now_add=True(データ生成時の現在日時を設定) を指定したためです。

追加されました。追加されたデータのタイトルをクリックして編集してみます。

何か変更して「保存」をクリック。

変更されました。

11. View の設計

掲示板と言っても画面の種別が様々ですが、今回は練習用なので、

  • 投稿されたコメントの表示 + 投稿フォーム
  • 投稿フォームのデータ送信先

で作ってみます。

まず、URLを決めます。今回は以下のように設定します。

  • 投稿されたコメントの表示 + 投稿フォーム = /bb/
  • 投稿フォームのデータ送信先 = /bb/post
vi urls.py
urlpatterns = patterns('',
    # 下2行を追記
    (r'^bb/$', 'vpstest.bb.views.index'),
    (r'^bb/post/$', 'vpstest.bb.views.post'),
)

12. View の実装

練習として最もシンプルな view を実装してみます。

vi bb/views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("hello world.")

先程、urls.py に記述した vpstest.bb.views.index は、この、views.py の index メソッドが実行されます。開発用 httpd を起動して、ブラウザで http://VPSのIPアドレス:8000/bb/ にアクセスして、

hello world.

と表示されるか確認します。

では、本格的に view を実装します。簡単な処理の説明は以下のとおり。
・データベースからすべての投稿を取得する(objects.all)
・テンプレート(bb/index.html) を取得する
・テンプレートに展開するデータの定義(‘all_comment’: all_comment)
・最後に テンプレートを出力し、出力内容を HttpResponse で返す

vi bb/views.py
from django.views.generic.simple import direct_to_template
from vpstest.bb.models import BB

def index(request):
    all_comment = BB.objects.all()
    return direct_to_template(request, 'bb/index.html',
            {'all_comment': all_comment})

13. Template の実装

view は作りましたが、テンプレートがまだです。ということで次は、テンプレートを作成します。
まず、テンプレートの置き場所を定義。

vi settings.py
TEMPLATE_DIRS = (
    '/var/www/django/vpstest/templates'
)

定義したテンプレート用ディレクトリを作成します。

mkdir /var/www/django/vpstest/templates
mkdir /var/www/django/vpstest/templates/bb

テンプレートを作成。簡単に解説すると・・・

  • view で定義していた all_comment が空じゃなければ、投稿分だけ、タイトル、名前、投稿時間、コメント内容を出力する
  • view で定義していた all_comment が空だと no comment とだけ表示して終わり

    ※ 普通、ここにHTMLのヘッダ部分とかCSSとか書きません。あくまで練習ってことで。。

    vi templates/bb/index.html
    <!DOCTYPE HTML>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Django で作る掲示板</title>
    
    <style type="text/css">
        div.post{
            border: 1px solid #cccccc;
            padding:5px;
            margin:5px;
        }
        div.title {
            background-color:#e2eef7;
        }
        div.date {
            text-align:right;
            margin-right:10px;
        }
        div.comment {
            padding:5px;
        }
    </style>
    </head>
    <body>
    
    <!-- データ繰り返し表示 開始 -->
    {% if all_comment %}
        {% for bb in all_comment %}
        <div class="post">
            <div class="title">{{ bb.title }}</div>
            <div class="date">{{ bb.name }} @ {{ bb.post_date }}</div>
            <div class="comment">
                {{ bb.comment }}
            </div>
        </div>
        {% endfor %}
    {% else %}
    no comment
    {% endif %}
    <!-- データ繰り返し表示 終了 -->
    
    </body>
    </html>
    

    開発用 httpd で確認してみます。ブラウザで http://VPSのIPアドレス:8000/bb/ にアクセス。

    前の手順で管理サイトから追加したデータが表示されました。

    14. 投稿フォームの作成

    投稿されたデータをすべて見れるようになったので、次は、投稿フォームを作ってデータを追加できるようにします。

    まず、テンプレートの編集。データ繰り返し表示完了の下に追記します。

    vi templates/bb/index.html
    省略
    <!-- データ繰り返し表示 終了-->
    
    <!-- 投稿フォーム 開始 -->
    <div class="post">
        <form action="/bb/post/" method="post">
            {% csrf_token %}
            {{ form.as_p }}
           <input type="submit" value="送信">
       </form>
    </div>
    <!-- 投稿フォーム 終了 -->
    • {% csrf_token %}:CSRF対策用のタグが埋め込まれます。これを formタグ内に書かないとデータ追加ができません。参考:CSRF
    • {{ form.as_p }}:後述する、django.forms の定義内容からフォームを生成するニクイやつ。

    次にフォーム処理用のクラスを作成します。

    • validation(データの検証)ができる
    • テンプレートにフォーム要素を出力できる
    • クリーニングされたデータを利用できる
    vi bb/forms.py
    from django.forms import ModelForm
    from vpstest.bb.models import BB
    
    class BBForm(ModelForm):
        class Meta:
            model = BB

    各データを個別に定義できますが、ModelForm を利用することにより、Model定義から validation を設定してくれます。参考:モデルからフォームを生成する

    最後に view を編集します。

    vi bb/views.py
    from django.views.generic.simple import direct_to_template
    from django.shortcuts import redirect  ←追記
    from vpstest.bb.models import BB
    from vpstest.bb.forms import BBForm  ←追記
    
    def index(request):
        all_comment = BB.objects.all()
        return direct_to_template(request, 'bb/index.html',
                {'all_comment': all_comment, 'form': BBForm()})
    
    def post(request):
        if request.method != 'POST':
            return redirect('/bb/')
    
        form = BBForm(request.POST)
        if form.is_valid():
            bb = BB()
            bb.title = form.cleaned_data['title']
            bb.name = form.cleaned_data['name']
            bb.comment = form.cleaned_data['comment']
            bb.save()
    
        dict = {'form': form}
        dict['all_comment'] = BB.objects.all()
        return direct_to_template(request, 'bb/index.html', dict)

    簡単に解説

    • index メソッドの変更:’form’: BBForm() が増えてます。前の手順でテンプレートに投稿フォームを追加したので、そこで使うためです
    • post メソッドその1:リクエストがPOST以外だったら、/bb/ にリダイレクトさせます
    • post メソッドその2:form = BBForm でリクエストを処理
    • post メソッドその3:form.is_valid で validation の成否判定
    • post メソッドその4:validation が通ったら、データを insert します。各データは、cleaned_data で綺麗になったデータをセットしてます。
    • post メソッドその5:最後に全投稿をテンプレートにセットして出力

    動作確認

    開発用 httpd を起動

    python manage.py runserver VPSのIPアドレス:8000

    ブラウザで掲示板にアクセス

    http://VPSのIPアドレス:8000/bb/

    ・Title:適当に入力
    ・Name:適当に(ry
    ・Comment:てきt(ry
    ・送信

    追加されました。

    試しにエラーになるようにどれか空にして送信してみます。(今回は、全部必須にしてあるので)

    無事エラーになりました。自動生成されるフォーム要素、エラーが気に食わない場合は自由に編集できるそうです。参考:フォームの操作

    とりあえず、データベースから select して表示、データベースへの insert まで出来たので今回はこれで終了します。そのうち、更新処理(update)、削除処理(delete)も時間があったら書こうと思います。

2 Responses to ServersMan@VPS Django で掲示板を作る

  1. zaka より:

    はじめまして、zakaと申します。
    serversmanを使ってdjangoを運用されている方はいないだろうかと、情報を探していて
    たどり着きました。とても参考になりました。ありがとうございます!
    ただ、1点表記で記述ミスと思われる点があったのでお知らせいたします。

    8. モデルの定義
    の、models.pyの記述内容の一番最終行に余計なタブが入っているようです。
    admin.site.register(BB)
    のところになります。

    コピペしなければ気がつく場所だとは思うのですが。

  2. ても より:

    うぉー、これは痛いミスを・・・。報告ありがとうございます。修正しました。

コメントを残す

メールアドレスが公開されることはありません。

Top