よく忘れるのでメモ書き。versionは、1.1.0 alpha。svnで取得。ただ1.0のドキュメントを見ながら作ったので、1.0と変化無し。
練習として、もの凄く簡単な掲示板を作成。
複数の板と言われるものがあって、その板にそれぞれコメントを投稿していく形。投稿したコメントは削除、変更はできない物とする。なお板はAdminしか追加/削除/変更ができない物とする。
プロジェクト名は「notepad」アプリケーション名は「board」としました。
Model -- データベース --
データベース(model)は、threadBoardと云う板と、書き込んだ内容を溜めるthreadCommentsの二つ。
DjangoのAdminからのみthreadBoardを追加するようにするため、admin.site.registerを設定。
threadCommentsは投稿フォームを作成する必要があるので、threadCommentsFormというModelFormを作成。
その際に、excludeで、入力不要な項目を設定しておく
なお、このthreadBoardのthreadTitleにuniqe属性を付けるの忘れてた…
from django.db import models from django.forms import ModelForm # Create your models here. class threadBoard (models.Model): threadTitle = models.CharField(max_length=100) # 板のタイトル pubData = models.DateTimeField() # 板を作成した日時 def __unicode__ (self): return self.threadTitle; class threadComments(models.Model): board = models.ForeignKey(threadBoard) # 投稿した板 cmtTitle = models.CharField(max_length=50) # コメントタイトル cmtName = models.CharField(max_length=50) # 投稿者名 pubDate = models.DateTimeField(auto_now_add=True) # 投稿日時 cmt = models.TextField() # 投稿内容 fromIP = models.IPAddressField() # 投稿者IP def __unicode__ (self): return self.board, self.cmt class threadBoardForm(ModelForm): class Meta: model = threadBoard class threadCommentsForm(ModelForm): class Meta: model = threadComments exclude = ('board','pubDate','fromIP' ) from django.contrib import admin admin.site.register(threadBoard) admin.site.register(threadComments)
URL
どこにアクセスしたらどうなるとか、そう言うのを設定。*1
まず、下記のリストのようなURLインターフェースにする。
- /admin/(.*)
- Djangoの管理画面へ
- /entry/([^/]+)/?
- 投稿処理をする
- /([^/]+)/?
- 板の内容を表示
- /
- トップ画面。板一覧を表示
次にurls設定。
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'^notepad/', include('notepad.foo.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: # (r'^admin/doc/', include('django.contrib.admindocs.urls')), # Uncomment the next line to enable the admin: (r'^admin/(.*)', admin.site.root), # Getting the comment from user. (r'entry/(?P<boardName>[^/]+)/?', 'notepad.board.views.submit'), # Show the boards (r'(?P<boardName>[^/]+)/?$', 'notepad.board.views.board'), # Top Directory (r'^$', 'notepad.board.views.top'), )
ViewController
アクセスがあったら表示する処理。
次に書くのは関数名と、その処理内容。関数名は上記のURLsに書いている。'notepad.board.views.*'の*と合わす事。*2
- subject
- 投稿処理をする。板がない場合や、システム的に不適切な投稿内容の場合は「/」に飛ばしたり404を返す。*3データ、IPアドレス等のシステム的に安心なデータを入れたい場合は、一度POSTの内容をsave(commit=False)でテイントチェックというか安全なコードにする。その返り値は安全なデータを持ったModelFormオブジェクトなので、プロパティに追加していく形になる。下記で云うと、valid_post.fromIP。なお、ForeignKeyのプロパティを指定する場合は、Modelオブジェクトを代入すれば自動的にリレーションを貼る。下記で云う、vavlid_post.boardの事。
- board
- 板の内容を表示する。そのまんまな処理。ほとんどテンプレート側の処理。
- top
- トップ画面を表示する。板のタイトルを表示させて、それぞれにリンクを貼る。
from django.shortcuts import get_object_or_404,render_to_response from django import forms from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from notepad.board.models import threadBoard, threadComments, threadCommentsForm def submit (req, boardName = ""): if boardName == "": return HttpResponseRedirect("/") boardInfo = get_object_or_404(threadBoard, threadTitle__exact = boardName) if req.POST: post = req.POST.copy() form = threadCommentsForm(post) if form.is_valid(): valid_post = form.save(commit=False) valid_post.board = boardInfo valid_post.fromIP = req.META['REMOTE_ADDR'] valid_post.save() return HttpResponseRedirect(reverse('notepad.board.views.board', args=(boardInfo.threadTitle,))) return HttpResponseRedirect("/") # - def board (req, boardName = ""): if boardName == "": return top(req) boardInfo = get_object_or_404(threadBoard, threadTitle__exact=boardName) cmt = threadComments.objects.filter(board__threadTitle__exact = boardName) return render_to_response('board.html', {'comments':cmt, 'board':boardInfo, 'form':threadCommentsForm(), } ) # - def top (req): boardList = threadBoard.objects.all() return render_to_response('index.html', {'boards': boardList})
テンプレート
大事だけど一番面倒な所。今回は煩わしかったので、本当に質素なHTMLでテンプレートを書きました。
なおテンプレートの指定は、上記のViewで云うとrender_to_responseの第一引数に書かれているファイル名が、テンプレート名になる。
- board.html
- board関数が呼び出す。これは、板を開いた時に呼び出される。つまり投稿内容を表示し、投稿フォームを表示させる。
- index.html
- top関数が呼び出す。板一覧表示。
Board.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"> <head> <meta http-equiv="Content-Style-Type" content="text/css" /> <meta http-equiv="Content-Script-Type" content="text/javascript" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <link rel="stylesheet" href="/media/index.css" type="text/css" /> {% block css_block %}{% endblock css_block %} <title>note Pad</title> </head> <body> <h1><a href="/">note Pad</a></h1> <div class="top_menu_bar"> <span><a href="/">Top</a></span> <span><a href="http://www.djangoproject.com/">Powerd By django</a></span> </div> <div class="form"> <form action="/entry/{{board.threadTitle}}/" method="POST"> {{ form.as_p }} <input type='submit' /> </div> <div class="board"> {% for comment in comments %} <p> {{ comment.cmtTitle }}<br /> {{ comment.cmtName }}<br /> {{ comment.cmt }} </p> {% endfor %} </div> </body> </html>
index.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"> <head> <meta http-equiv="Content-Style-Type" content="text/css" /> <meta http-equiv="Content-Script-Type" content="text/javascript" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <link rel="stylesheet" href="/media/index.css" type="text/css" /> {% block css_block %}{% endblock css_block %} <title>note Pad</title> </head> <body> <h1><a href="/">note Pad</a></h1> <div class="top_menu_bar"> <span><a href="/">Top</a></span> <span><a href="http://www.djangoproject.com/">Powerd By django</a></span> </div> <div class="board"> {% for board in boards %} <a href="/{{board.threadTitle}}/">{{board.threadTitle}}</a> {% endfor %} </div> </body> </html>
設定 -- settings.pyの事。
ほとんどは変わりなし。個人的に良く書く書き方があるのでメモ書き。
TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. os.path.abspath(os.path.dirname(__file__)) + "/template", # '/home/notepad/workshop/notepad/template', ) # i18n ugettext = lambda s: s LANGUAGES = ( ('ja', ugettext('Japanese')), ('en', ugettext('English')), ) # Cache CACHE_BACKEND = 'dummy:///'
0.96からの変更点
一番大きいのが、ModelFormの使用。Manipulatorと言うのを0.96の時は使っていたので、それ一式が使い物にならなくなり、全て書き直し。
他は、Modelのmaxlengthがmax_lengthに変更かしら…