Django の概要

Django は変転の激しいニュースルーム環境で開発された経緯から、よくある Web 開発タスクを迅速かつ簡単化するように設計されています。ここでは Django による データベースを使った Web アプリケーション開発をざっと見てみましょう。

このドキュメントの目的は、 Django の技術的な仕様について述べ、どのように動作するかを理解してもらうことにあり、チュートリアルやリファレンスではあり ません。 (とはいえ、チュートリアルもリファレンスも別に用意していますよ!) プロジェクトを作成する準備ができたら、 チュートリアルを始める ことも、 より詳細なドキュメントを読む こともできます。

モデルの設計

データベースなしで Django を使うこともできますが、 Django には Python コードでデータベースのレイアウトを記述した オブジェクトリレーショナルマッパー (object-relational mapper) が付属しています。

データモデル構文 ではモデルを表現するさまざまな方法が提供されています。これまでのところ、長年におけるデータベーススキーマの問題を解決してきた実績があります。 簡単な例を示しましょう:

news/models.py
from django.db import models


class Reporter(models.Model):
    full_name = models.CharField(max_length=70)

    def __str__(self):
        return self.full_name


class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)

    def __str__(self):
        return self.headline

モデルのインストール

次に、データベーステーブルを自動で作成する Django のコマンドラインユーティリティを実行します。

$ python manage.py makemigrations
$ python manage.py migrate
...\> py manage.py makemigrations
...\> py manage.py migrate

makemigrations コマンドは、利用できるモデルを全て見て、まだ作成されていないテーブルを作るためのマイグレーションを生成します。migrate コマンドは、マイグレーションを実行し、実際にデータベースにテーブルを作成します。また、必要に応じて、より強力にスキーマを制御する 機能も提供します。

自動生成される API で楽しむ

これだけで、制約のない充実した Python API を使って自分のデータにアクセスできます。API はオンザフライで生成され、コードを作成する必要はありません:

# Import the models we created from our "news" app
>>> from news.models import Article, Reporter

# No reporters are in the system yet.
>>> Reporter.objects.all()
<QuerySet []>

# Create a new Reporter.
>>> r = Reporter(full_name="John Smith")

# Save the object into the database. You have to call save() explicitly.
>>> r.save()

# Now it has an ID.
>>> r.id
1

# Now the new reporter is in the database.
>>> Reporter.objects.all()
<QuerySet [<Reporter: John Smith>]>

# Fields are represented as attributes on the Python object.
>>> r.full_name
'John Smith'

# Django provides a rich database lookup API.
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__startswith="John")
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains="mith")
<Reporter: John Smith>
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
    ...
DoesNotExist: Reporter matching query does not exist.

# Create an article.
>>> from datetime import date
>>> a = Article(
...     pub_date=date.today(), headline="Django is cool", content="Yeah.", reporter=r
... )
>>> a.save()

# Now the article is in the database.
>>> Article.objects.all()
<QuerySet [<Article: Django is cool>]>

# Article objects get API access to related Reporter objects.
>>> r = a.reporter
>>> r.full_name
'John Smith'

# And vice versa: Reporter objects get API access to Article objects.
>>> r.article_set.all()
<QuerySet [<Article: Django is cool>]>

# The API follows relationships as far as you need, performing efficient
# JOINs for you behind the scenes.
# This finds all articles by a reporter whose name starts with "John".
>>> Article.objects.filter(reporter__full_name__startswith="John")
<QuerySet [<Article: Django is cool>]>

# Change an object by altering its attributes and calling save().
>>> r.full_name = "Billy Goat"
>>> r.save()

# Delete an object with delete().
>>> r.delete()

作業場 (scaffold) ではなく完成品 (whole house) の、動的な admin インタフェース

モデルが定義されると、Django は自動的にプロ仕様の本番仕様の 管理インターフェース -- 認証されたユーザがオブジェクトを追加、変更、削除できるウェブサイトを作成できます。必要なステップは、管理サイトにモデルを登録することだけです。:

news/models.py
from django.db import models


class Article(models.Model):
    pub_date = models.DateField()
    headline = models.CharField(max_length=200)
    content = models.TextField()
    reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
news/admin.py
from django.contrib import admin

from . import models

admin.site.register(models.Article)

サイトの編集はスタッフ、顧客、もしくはあなた自身の手で行われるものであり、 コンテンツの管理だけのためにバックエンドインタフェースを作りたくはない、という思想がここにはあります。

Django アプリケーションを作成するときの典型的なワークフローは、 モデルを作成し、 admin サイトを組み上げてできるだけ早期に立ち上げ、スタッフ (や顧客) がデータを投入できるようにしておいてから、データを公開するための方法を開発してゆくというものです。

URL を設計する

すっきりとして洗練された URL スキームは、高品質な Web アプリケーションを実現する上で重要な要素です。 Django は美しい URL の設計を助け、 .php.asp のような粗雑な部分を URL に入れさせません。

アプリケーションの URL を設計するには、 URLconf と呼ばれる Python モジュールを一つ作成します。 URLconf はいわばアプリケーションの目次にあたり、 URL のパターンと Python のコールバック関数とを対応づけています。 URLconf はまた、 URL と Python コードを疎結合にする働きも持っています。

Reporter/Article の例では、 URLconf は以下のようになります:

news/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path("articles/<int:year>/", views.year_archive),
    path("articles/<int:year>/<int:month>/", views.month_archive),
    path("articles/<int:year>/<int:month>/<int:pk>/", views.article_detail),
]

上のコードは、 URL パスを Python のコールバック関数("views")にマッピングしています。 パス文字列は、パラメータタグを使用して URL から値を取得します。 ユーザがページをリクエストすると、Django は各パスを順番に実行し、要求された URL に最初に一致したパスで停止します。 (それらのどれとも一致しない場合、Django は特殊なケースである404ビューを呼び出します。)パスはロード時に正規表現にコンパイルされるので、これらは非常に高速に動作します。

URL パターンの1つが一致すると、Django は与えられたビューを呼び出します。これは Python の関数です。 各ビューは、リクエストのメタデータを含むリクエストオブジェクトと、パターンで捉えられた値を渡します。

例えば、ユーザが "/articles/2005/05/39323/" という URL をリクエストすると、 Django は news.views.article_detail(request, year=2005, month=5, pk=39323) のような関数呼び出しを行います。

ビューの自作

各ビューには二つの役割があります: 一つはリクエストされたページのコンテンツを含む HttpResponse オブジェクトを返すこと、もう一つは Http404 のような例外の送出です。それ以外の処理はユーザ次第です。

一般的に、ビューはパラメーターに従ってデータベースからデータを取り出し、テンプレートをロードして、取り出したデータでテンプレートをレンダリングします。 上の year_archive のビューを例に示しましょう:

news/views.py
from django.shortcuts import render

from .models import Article


def year_archive(request, year):
    a_list = Article.objects.filter(pub_date__year=year)
    context = {"year": year, "article_list": a_list}
    return render(request, "news/year_archive.html", context)

この例では Django の テンプレートシステム を使っています。テンプレートシステムは、強力な機能をいくつも備えながらも、非プログラマが使いこなせる程度に簡単な仕組みです。

テンプレートを設計する

上のコードでは news/year_archive.html という名前のテンプレートをロー ドしています。

Django はテンプレートの重複を最小限にする為に、テンプレートの検索パスを持っています。Djangoの設定ファイルの中で、テンプレートをチェックする DIRS にディレクトリのリストを指定します。最初のディレクトリにテンプレートが存在しなかった場合、2番目をチェックし、以降も同様にチェックが続きます。

さて、 news/year_archive.html が見つかったとしましょう。テンプレートは以下のように書かれています:

news/templates/news/year_archive.html
{% extends "base.html" %}

{% block title %}Articles for {{ year }}{% endblock %}

{% block content %}
<h1>Articles for {{ year }}</h1>

{% for article in article_list %}
    <p>{{ article.headline }}</p>
    <p>By {{ article.reporter.full_name }}</p>
    <p>Published {{ article.pub_date|date:"F j, Y" }}</p>
{% endfor %}
{% endblock %}

変数は二重の波括弧で囲まれています。 {{ article.headline }} は、「article の headline という属性の出力」を表しています。とはいえ、ドット表記は属性の検索に使われるだけではありません。辞書の検索や、インデクス指定、関数呼び出しも行えます。

{{ article.pub_date|date:"F j, Y" }} で、 Unix スタイルの「パイプ」 (文字 “|”) を使っていることに注意して下さい。これはテンプレートフィルターと呼ばれ、変数の値にフィルターをかけるためのものです。この例では、フィルタによって Python の datetime オブジェクトを指定の形式にフォーマットしています (PHP の date 関数に似ていますね) 。

フィルターはいくつでも好きなだけ繋げることが出来ます。また、独自の Python コードを実行する カスタムテンプレートフィルタカスタムテンプレートタグ を書くことも出来ます。

最後に、 Django にはテンプレートの継承という概念があります。 継承を宣言しているのは {% extends "base.html" %} の部分です。このタグは「まず ‘base’ というテンプレートをロードせよ。このテンプレートにはいくつかのブロックが定義されているが、それらのブロックの中身を以下のブロック定義で埋めよ」という命令です。要するに、テンプレートを継承すると、各テンプレートごとに固有の定義だけを記述すればよくなり、テンプレート間の冗長性が劇的に減るのです。

ここでよくある“base.html” テンプレートで、 静的ファイルの配信 を含む例をあげます:

templates/base.html
{% load static %}
<html>
<head>
    <title>{% block title %}{% endblock %}</title>
</head>
<body>
    <img src="{% static 'images/sitelogo.png' %}" alt="Logo">
    {% block content %}{% endblock %}
</body>
</html>

簡単に言えば、サイトのルックアンドフィール(サイトのロゴ)を定義し、子テンプレートが埋めるための「穴」を提供します。つまり、サイトの再設計は、ベーステンプレートという1つのファイルを変更するだけで行うことができます。

また、子テンプレートを再利用しながら、異なるベーステンプレートで複数のバージョンのサイトを作成することもできます。Django の作者はこのテクニックを使って、新しいベーステンプレートを作成するだけで、印象的に異なるモバイルバージョンのサイトを作成しています。

他のシステムを使いたければ、必ずしも Django のテンプレートシステムを使う必要はないということに注意してください。 Django のテンプレートシステムは Django のモデルレイヤと部分的にしっかり組み合わさっていますが、絶対に使わねばならないということではありません。さらに言えば、 Django のデータベース API を使う必然性もありません。別のデータベース抽象化レイヤを使っても構いませんし、 XML ファイルやディスク上のファイルを読み込んでも構いません。何でもやりたいことをできるのです。Django の構成要素 – モデル、ビュー、テンプレー ト – は、互いに切り離して利用できるのです。

これらはほんの一部にすぎません

以上、 Django の機能についてざっと紹介してきました。 Django は他にもまだまだ便利な機能を備えています:

次のステップは Django をダウンロードし、 チュートリアル を読み、 コミュニティに参加する ことです。ご興味を持っていただきありがとうございました。

Back to Top