Django : チュートリアル

Last Change: 26-Apr-2016.
author : qh73xe

このページでは Django を使用してとりあえず何か web アプリを作成してみます. ここで作成するのは, Dangoドキュメントにある簡単な投票アプリです.

このページは以下のサイトを参考に作成しました.

Django の導入

Django の導入は pip から行いました.

$ sudo pip install Django

基本的に Unix 系の OS を使用しているなら,これで問題ないでしょう. ただし, virtualenvvirtualenvwrapper を使用している場合, そちらの方が気軽にできます.

Project の作成

では, Django を使用して Web アプリを作成してみましょう. まずは, 適当な作業ディレクトリ (何でもよいです) に移動して, 端末上で以下のコマンドを入力します.

$ django-admin.py startproject testDjango

重要なのは $ django.py startproject の部分です. これは Django を使用してアプリを作成する際のコマンドです.

このコマンドを打つと,直下のディレクトリに最後の引数に渡したディレクトリが作成されます. これらのファイルがアプリケーションの基本になります.

なお, Django は,それ自身でテスト用のポートを開くこともできますので, Web サーバーのドキュメントルートにおく必要はありません.

testDjango.    : 単なる入れ物
├── manage.py  : Djangoプロジェクトを操作するためのコマンド
└── testDjango : プロジェクトの本体. Import の時に使用する名前でもある
    ├── __init__.py : このディレクトリがライブラリであることを宣言するファイル
    ├── settings.py : このプロジェクトの設定ファイル
    ├── urls.py     : URL宣言
    └── wsgi.py     : WSGI互換のあるサーバーでプロジェクトを動かすためのエントリーポイント

というわけで,基本的に厄介な部分をテンプレ化してくれています. 後は setting.py をシコシコして, manage.py でカンバって行けばなんとかなります.

注釈

__init__.py について

このディレクトリが Python パッケージであることを Python に知らせるための空のファイルです。 これがどのようなことを意味しているのかというと,この後作成していくアプリケーションは 一種の python パッケージであるということです.

Django では複数のファイルを編集していくことで web アプリケーションを作成していく のですが,こうすることによってファイル間の連携が取りやすくなります.

基本設定

Database の設定

さて,まずは testDjango/settings.py の編集を行います. ここではDjango で使用する Database を決定します. デフォルトでは SQlite を使用するようになっています. とりあえず,急ぎの場合は基本的にこれを使用するのが楽かと思います.

使用するデータベースを変更したい場合,使用したいデータベースをシステムに導入した 後で, settings.py の DATABASES にある ‘default’ 以下を編集します. 具体的な設定内容を以下に示します.

  • ENGINE : データベースシステム名
  • Name : SQlite ファイル名

注釈

具体例 : PostgreSQL を使用したい場合

settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'mydatabase',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': '5432',
    }
}

タイムゾーンの設定

続いてタイムゾーンの設定を行います. これは settings.py の TIME_ZONE を編集します. デフォルトでは UTC になっています.

settings.py:

TIME_ZONE = 'Asia/Tokyo'
USE_TZ = False

INSTALLED_APPS の設定

最後に INSTALLED_APPs の設定を確認します. ここは今回作成しているシステムで実際に稼働するアプリケーションを記述する場所です.

デフォルトでは以下のように記述されています.

settings.py

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
)
  • django.contrib.admin - adminサイト
  • django.contrib.auth - 認証システム
  • django.contrib.contenttypes - Content-Type フレームワーク
  • django.contrib.sessions - セッションフレームワーク
  • django.contrib.messages - メッセージングフレームワーク
  • django.contrib.staticfiles - 静的ファイルを管理するためのフレームワーク

後で,新規のアプリケーションを作成,追加するわけですが,このように Webアプリケーションなら必要であると思われる機能の多く(たいていは作成するのが退屈なもの)は すでに組み込みがなされています.

これらのアプリケーションは少なくとも一つはデータベースを使用します. そのため,今回作成しているアプリケーション用のデータベースを作成する必要があります.

$ python manage.py migrate

警告

manage.py migrate について

このコマンドは Djnago 1.4 の際には無かったコマンドです. Django 1.7 を使用している方が日本語のチュートリアルを試している場合, ここでハマるかもしれません.

なお,古いバージョンでは以下のように記述します.

$ python manage.py syncdb

開発用サーバーを起動してみる

ここまでできたら,デバック方法の確認です. とりあえず,作成されたディレクトリに入って以下のコマンドを入力します.

$ python manage.py runserver

すると以下のような表示が現れるかと思います.

Validating models...

0 errors found
May 07, 2014 - 13:57:34
Django version 1.6.4, using settings 'testDjango.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

ブラウザを起動して以下のURLにアクセスします.

“It Worked!” という表示が出たら成功です.

このように Django はどのディレクトリにいてもブラウザから結果を確認できます.

アプリケーションの作成

では,いよいよ Web アプリを作成していきましょう.

$ python manage.py startapp polls

これで,testDjango の中に polls が作成されました.

注釈

Projects vs. apps

ここまでの説明で,少し混乱を招く概念として, Projects と apps というものがあります.

Django のなかで app とは何かをする Webアプリケーション のことです. 例えば,ログ管理や,投票などの機能です.

一方,Project は特定の web サイトの設定の集まりです. これは上記で行ってきた作業のように,データベースには何を使うかだとか, Time_ZONE は何処かだとか,どの APP を使うのかだとかを決める作業です.

中身を確認すると以下のような構成になっています.

poll:

polls
├── __init__.py
├── admin.py
├── migrations
│   └__init__.py
├── models.py
├── tespy
└── views.py

これらのファイルのうち,特に重要なファイルは models.pyviews.py です.

  • models.py : アプリケーションで使用するデータベースの構成を記述
  • views.py : アプリケーションで使用する機能を記述

モデルの作成

まずは models.py を編集してみましょう. 今回のチュートリアルでは簡単な投票機能を作成します.

これに必要なデータベースを考えると,以下のテーブルが必要でしょう.

  • 質問内容を保存するテーブル
    • 質問内容
    • 質問が作成された日時
  • 投票結果を保存するテーブル
    • どの質問に対する回答か
    • 回答項目
    • 回答結果

これをスクリプトに治すと以下のような内容になります.

models.py:

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')


class Choice(models.Model):
    question = models.ForeignKey(Question)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

モデルの有効化

モデルの作成が終了したら,Project に App を登録する必要があります. 以下のように編集しましょう.

mysite/settings.py:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
)

設定ファイルを書き換えたので,設定に合わせたデータベースを作成します. それには以下のコマンドを入力します.

$ python manage.py makemigrations polls
$ python manage.py sqlmigrate polls 0001
$ python manage.py migrate

API を操作する

上の作業が無事終了した場合,データベースを django の方から操作することができるよ うになります.

$ python manage.py shell
  • Ipython を導入している場合,Ipython で起動されます.

例えば上記の例での Question と Choice を操作します.

>>> from polls.models import Question, Choice
# Question のすべての要素を表示します
# 何も入れていないので空欄になります.
>>> Question.objects.all()
[]

では要素を追加していきましょう.

Question には時間的な要素がありますので django の時間処理用のライブラリも読み込みます.

>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

要素をデータベースに保存するには以下の処理を行います.

>>> q.save()

保存した要素を検討します.

>>> q.question_text
"What's new?"

無事要素の保存ができているようです. ただし,現状では Question のすべての要素を表示しようとすると以下のような感じにな ります.

>>> Question.objects.all()
[<Question: Question object>]

これではあまりに人道的ではないので models.py を変更します.

polls/models.py:

from django.db import models
class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

class Choice(models.Model):
    # ...
    def __str__(self):
        return self.choice_text

上記のようにすると少しいい感じになります. ついでなので models.py をもう少し加工してみます.

polls/models.py:

import datetime
from django.db import models
from django.utils import timezone

class Question(models.Model):
    # ...
    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

では API で遊んで見ましょう. とりあえず, python manage.py shell です.

>>> from polls.models import Question, Choice
>>> Question.objects.all()
[<Question: What's new?>]

先ほど設定した通り,オブジェクトには question_text の内容が反映されました. ではデータをいろいろといじってみます.

Django のデータベースにアクセスし要素を選択する場合, filter メゾットを使用するとよいです.

>>> Question.objects.filter(id=1)
[<Question: What's up?>]
>>> Question.objects.filter(question_text__startswith='What')
[<Question: What's up?>]

ある要素を直接取得するには get メゾットを使用します.

>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

データベースを作成する場合,primary key を使用する機会が多いです. そのため, Django では自動で primary key を作成します.

>>> Question.objects.get(pk=1)
<Question: What's up?>

上で作成した独自メソッドが機能するかも確かめてみます.

>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

リレーションを貼った子要素にアクセスするには <子要素名>_set とします.

>>> q = Question.objects.get(pk=1)
>>> q.choice_set.all()
[]

選択肢が何もないのは面白くないので,

>>> q.choice_set.create(choice_text='Not much', votes=0)
>>> q.choice_set.create(choice_text='The sky', votes=0)
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)

c はインスタンスです. これは choice オブジェクトです. ここから親要素にアクセスするには以下のようにします.

>>> c.question
<Question: What's up?>

q インスタンスの子要素を一覧にします.

>>> q.choice_set.all()
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
>>> q.choice_set.count()
3

要素を削除する場合以下のようにします.

>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()

注釈

スクリプトから Djnago API を叩くには

たとえば,ダミー用のデータを大量に入力する際など, 通常の python スクリプトから Djnago のデータベースにアクセスしたい場合も あるかと思います.

このような場合,以下のようにします.

$ export DJANGO_SETTINGS_MODULE=testDjango.settings
  • “=” の後は,python 的に setting.py までのパスを書きます.

その上で python 側では以下のようにします.

import django
django.setup()

以降は Django の API の通りに作業できます.

  • この作業を行い AttributeError が出る場合,Djnago のバージョンが古いです

管理者画面

さて,ここからは djnago の管理者画面の話をします. ここも Django 1.4 とは作業内容が異なります.

まずは管理者アカウントを作成する必要があります.

$ python manage.py createsuperuser

コマンドを入力すると以下のことを聞かれます.

  • Username:
  • Email address:
  • Password:

これらは任意の設定で構いません. とりあえず,ここでは Username: admin とした上で作業をしていきます.

警告

djnago 1.4 の場合

django 1.4 を使用している場合この作業は不要です.

サーバーを起動する

続いてサーバーを起動しましょう. $ python manage.py runserver ですね.

http://127.0.0.1:8000/admin にアクセスしてみてください.

するとログイン画面になると思います. ここに上で設定したユーザー名とパスワードを入力します.

Alternate Text

さて,ここからはこの管理画面を設定していきましょう. まずこの画面では Polls のデータ(つまり Question, Choice)が表示されていません.

Alternate Text

polls/admin.py を編集します.

polls/admin.py

from django.contrib import admin
from polls.models import Question

admin.site.register(Question)

これを追加すると管理画面に “Polls/Question” の項目が増えます.

Alternate Text

では Question に入って行きましょう.

Alternate Text

いろいろとボタンが見えると思います. 公式サイトではここのレイアウトに関する記述がありますが, このページでは一旦,後回しにします.

注釈

admin.py の編集中のサーバーに関して

admin.py を編集している最中にサーバーはどうしたらいいでしょうか? 複数の端末を操作できる場合,実はサーバーは放置しておいて大丈夫です. もちろん編集結果も自動で反映されます.

リレーションを貼った項目

ではリレーションを貼った項目を操作してみます. そのためには polls/admin.py に choice を追記しないと行けませんね.

polls/admin.py:

from django.contrib import admin
from polls.models import Choice, Question

# ...
admin.site.register(Choice)

こうすると,Choice の項目が増えますよね. でも,せっかくのリレーションを反映した形とはいえません.

こんな感じにするとよいでしょう.

polls/admin.py:

from django.contrib import admin
from polls.models import Choice, Question

class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 1

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': [' collapse']}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)

このようにすると各 Question の項目に Choice が付与されます.

Alternate Text

admin change list の変更

現状では http://127.0.0.1:8000/admin/polls/question/ のページでは 各 Question のタイトルのみが表示されています.

ここに提示する情報を追加するには以下のようにします.

polls/admin.py:

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date', 'was_published_recently')

表示のフィルターを追加するには polls/admin.pylist_filter を追加します.

polls/admin.py:

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_filter = ['pub_date']

この項目を複数個指定した場合以下のようになります.

polls/admin.py:

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_filter = ['pub_date', `question_text`]

プロジェクトテンプレートのカスタマイズ

上記の通り Django では面倒な仕事を事前にこなしてくれている場合が多いです. これらを再利用していくことでアプリ開発がより迅速になるでしょう.

テンプレートをカスタマイズするには templates ディレクトリを作成する必要があります.

まずはプロジェクトの設定ファイル(当然, testDjango/setting.py です) を 編集し, TEMPLATE_DIRS を設定しましょう.

testDjango/setting.py:

TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
  • BASE_DIR はデフォルトでは Djnago のプロジェクトルートです.

TEMPLATE_DIRS は Django のテンプレートをロードする際に,チェックされる検索パスです.

では,templates を作成し,admin というディレクトリを作りましょう. そして, デフォルトの Django admin template ディレクトリから admin/base_site.html をコピーします.

注釈

Django のソースファイルの場所について

Django のソースファイルの場所が分からない場合 python を起動し,以下のようにします

>>> import sys
>>> sys.path = sys.path[1:]
>>> import django
>>> print(django.__path__)

例えば私の環境の場合,以下のようにしました.

$ mkdir templates
$ mkdir templates/admin
$ cp /usr/lib/python2.7/site-packages/django/contrib/admin/templates/admin/base_site.html templates/admin/base_site.html

さて,このファイルを編集します. とりあえず,わかりやすくタイトル部分を変更しましょうか.

六行目(<h1 ...> で始まる部分です)を以下のように書き換えます.

<h1 id="site-name"><a href="{% url 'admin:index' %}">管理画面</a></h1>

するとタイトル部分が変わったことが確認できると思います.

View

さて,いよいよアプリケーションに機能を実装していきます. Djnago では具体的な機能を記述する部分を view と呼びます. View の基本的な役割は何らかの形で DB を操作し,それを HTML テンプレートに渡すことです. 今回作成している Poll アプリでは以下のような機能が必要かと思います.

  • Question “index page : 最近の Question を表示する.
  • Question “detail” page : Question の内容を示し, 投票用のフォームを表示する.
  • Question “results” page : それぞれの Question の結果を表示する.
  • Vote action : ある調査項目のある選択肢に対する投票を受け付ける.

ではやっていきましょう.

初めての view

polls/views.py に以下のように記述します.

polls/views.py

from django.http import HttpResponse
def index(request):
    return HttpResponse("Hello, world. You're at the polls index.")

続いて,この view が何処にアクセスした場合に機能するのかを定義します. polls の下に urls.py を作成します.

from django.conf.urls import patterns, url
from polls import views

urlpatterns = patterns('', url(r'^$', views.index, name='index'),)

その上で,root URLconf を設定します. これはプロジェクト全体の設定なので testDjango/urls.py ですね.

from django.conf.urls import patterns, include, url
from django.contrib import admin

urlpatterns = patterns('',
    url(r'^polls/', include('polls.urls')),
    url(r'^admin/', include(admin.site.urls)),
)

これで http://127.0.0.1:8000/polls/ にアクセスするとテキストが表示されると思います.

注釈

url の記法に関して

上記の記法は django 1.9 以降では、警告がでるかと思います. 新しい記法は以下の通り, patterns 関数を使用するのではなく、 単純に urlpatterns という名前のリストを作成します。

urls.py
1
2
3
urlpatterns = [
    url(r'^about/$', about, name='about'),
]

view の編集

では上記に上げた機能を一つずつ作成していきます. view はこんな感じでしょうか?

polls/views.py

def detail(request, question_id):
    # 質問の内容を表示する
    return HttpResponse("You're looking at question %s." % question_id)
def results(request, question_id):
    # 結果を表示する
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)
def vote(request, question_id):
    # 投票を表示する
    return HttpResponse("You're voting on question %s." % question_id)

これらの view を url に結びつけます.

polls/urls.py

from django.conf.urls import patterns, url
from polls import views

urlpatterns = patterns('',
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<question_id>\d+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>\d+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
)

これで html と DB を結びつけることができたかと思います.