【図解付まとめ】Djangoの最強入門書!手を動かしながらブログアプリ(CMS)を作成して脱初心者しよう!

本記事ではPythonのフルスタックWebフレームワークであるDjangoを入門書になります。

Djangoのインストールから仕組み・基本的な機能の習得を目的にしています。

本記事の理解・実践できれば一般的なWebアプリの開発スキルは取得できます。

なお本入門書を進めていくにあたり、以下のスキルは必須となります。

・HTML/CSSをコーディングできる人
・Pythonをコーディングすることができる人
・プログラミングでアプリやツール開発をした経験がある人

上記のスキルがない人はProgeteまたはドットインストールで学習することを強く推奨します。理解できずに挫折の原因になるからです。

本記事はアプリ開発に必要な情報を網羅的かつ適切な順序で説明しています。目次は大いに活用してください。

目次

Djangoのインストール

Djangoのインストールは非常に簡単です。

Python3系のインストールが完了後に以下のコマンドを実行すればOKです。

pip install django

インストールは上記のコマンドで可能ですが、それぞれのOSで違いがあります。詳細は自身の使用している環境ごとに以下の記事を参考にしてください。

LinuxにDjangoをインストールする手順はこちら

WindowsにDjangoをインストールする手順はこちら

MacOSにDjangoをインストールする手順はこちら

Docker上にDjango開発用コンテナを作成する方法はこちら

なおDjangoを本書のオススメはDocker上にDjango開発用コンテナを作成する方法をおすすめします。

WindowsにDockerをインストールする手順

Hello Worldで初めてのDjangoに挑戦

ここらは実際にDjangoを使用して「Hello World」のアプリを作成しましょう。

この章では何も考えずに実施してください。

  • 作成したファイルの役割
  • 実行したコマンドの意味
  • ディレクトリ構成

上記の内容のような詳細な説明は一旦省きます。次の章や別記事でその他の解説をしていきますので安心ください。

まずはDjangoのプロジェクト(Djangoの管理ファイル群)を作成します。

django-admin.py startproject project .

次に個別アプリファイル群を作成します。

python manage.py startapp helloworld

次にプロジェクト全体の設定ファイルであるproject/settings.pyに設定を追記していきます。

ALLOWED_HOSTS = ['*'] # '*'を設定


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'helloworld', # 追記
]

次にアプリの設定をしていきます。まずはhelloworld/views.pyでViewを作成します。

from django.http.response import HttpResponse

# Create your views here.
def helloworld(request):
    return HttpResponse('Hello World!')

次にURLディスパッチャーの設定していきます。

まずはプロジェクトのURLディスパッチャーを設定するためにproject/urls.pyに修正をします。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', include('helloworld.urls')),
    path('admin/', admin.site.urls),
]

次にアプリ側のURLディスパッチャーを設定します。そのためにproject/urls.pyを作成します。

先ほどのproject/urls.pyとは別のファイルになる点に注意ください。

from django.conf.urls import url

from . import views

urlpatterns = [
    url('', views.helloworld, name='helloworld'),
]

ここまで全てのファイルの作成は完了しました。Djangoサーバーを起動してみましょう。

python manage.py runserver 0.0.0.0:8000

ブラウザで「localhost:8000」 または「サーバIP:8000」にアクセスしてみましょう。

以下のようにHello Worldが表示されればDjangoが起動できました。

ここまでで初めてDjangoを使用してのHelloWorldは終わります。

以下により詳細な解説は記事がありますのであわせ確認してみください。

[超入門編] DjangoでHello WorldのWeb画面を実装しよう!

Djangoのメリット・デメリットは?

ここで簡単にDjangoを使うメリット・デメリットを説明したいと思います。

メリットデメリット準備中

Djangoとは何か?仕組み(MTV)を徹底解説!

DjangoとはMVT(Model/View/Templateの略)を使用したフレームワークのことを指します。

  • Model:データベースを操作する仕組み
  • Template:テンプレート(HTMLファイル)をWebページを表示する仕組み
  • View:ユーザからのリクエストをレスポンスを処理やModelとTemplateとの橋渡しをする仕組み

以下が処理のModel、Template、Viewの流れになります。

Model、Template、Viewの図を挿入予定。

しかしDjangoの処理アーキテクチャの全体図であり、他にも細かい処理はたくさんあります。

ですが、まずは上記の流れをイメージしてください。

仕組み準備中

では上記の流れとDjangoの構成ファイルがどこにマッピングしているかを確認してみます。

root/
 ├ helloworld/
 │ ├ admin.py
 │ ├ apps.py
 │ ├ models.py # ★Modelの役割
 │ ├ tests.py
 │ ├ urls.py
 │ └ views.py # ★Viewの役割
 │ 
 ├ project/
 │ ├ asgi.py
 │ ├ settings.py
 │ ├ urls.py
 │ └ wsgi.py
 │ 
 └ templates/
   └ helloworld/
     └ index.html # ★Templateの役割

MTVの流れを説明していたのに

  • 初めて登場したファイル群がある
  • HelloWorldで説明されていないファイルがある
  • MTVと関係ないファイルがこんなにあるの?

と心配すると思います。

私自身もこの点がDjangoの難しいところだと思います。なので心配しないでください。

ではそれぞれのファイルについて説明していきます。

ディレクトリファイル説明
helloworldadmin.py個別アプリの管理系の処理や設定を行うファイル
apps.py個別アプリの起動ファイル
models.py個別アプリデータモデルを処理するファイル
tests.py個別アプリの自動テストを行うファイル
urls.py個別アプリのURLディスパッチャーファイル
views.py個別アプリのユーザリクエスト・レスポンスの処理、ModelとTemplateの橋渡しを行う
procjectasgi.pyプロジェクトのASGI(非同期インターフェース)のファイル
settings.pyプロジェクトの設定ファイル
urls.pyプロジェクトのURLディスパッチャー
wsgi.pyプロジェクトのWebサーバとDjangoを繋ぐWSGI(Web Server Gateway Interface)のファイル
templates/helloworldindex.html個別アプリ用のテンプレート

色々なファイルがあり混乱してしまうと思いますが、まずは入門者は以下を抑えてほしいです。

アプリファイル群

・models.py:アプリのデータベース操作
・urls.py:アプリのURLディスパッチャー
・views.py:リクエスト・レスポンスの処理

プロジェクトファイル群

・settings.py:プロジェクトの設定ファイル
・urls.py:プロジェクト全体のURLディスパッチャー

ブログアプリを作成してDjango基本パターンをマスター

ここからDjangoを使用したブログアプリ(blog)を作り、より実践的なDjangoの機能を学んでいきたいと思います。

※ チュートリアルではToDoリストを多く作っているので今回は趣向を変えてブログアプリにしています。

以下の流れ作業を行なっていきます。

  1. アプリを作成してViewでTemplateを表示する
  2. データベースの設定とモデルの作成とマイグレーション
  3. AdminとSuperuserの作り方
  4. ルーティングのやり方
  5. データベースの情報をViewに表示する
  6. Styleを追加する
  7. Formの作成とデータの登録
  8. Formからデータの修正と削除
  9. 画像のアップロードできるFormを作成

本記事では最低限の解説のみ行っているため情報が不足している部分があります。

そのため各章の終わりに詳細な記事のリンクを作成しております。

必要な方は詳細版の記事を確認してみてください。

1.アプリを作成してViewでTemplateを表示する

ここではアプリを作成してViewとTemplateの連携をしてみましょう。

最初はトップページを単純に表示するアプリを作成します。

※helloworldアプリはそのままで大丈夫ですし、削除しても問題ありません。

まずはblogアプリを作成します。

python manage.py startapp blog

次にTemplateファイルを作成します。

blogと同じ階層にtemplates/blogディレクトリとindex.htmlを作成します。

 ├ blog/
 └ templates/
   └ blog/
     └ index.html

最後にblogディレクトリにurls.pyを作成します。

 └ blog/
   └ urls.py

最終的には以下のようにアプリ名blogとTemplatesを作成しましたでしょうか。

root/
 ├ blog/
 │ ├ migrations/
 │ │ └ __init__.py
 │ ├ __init__.py
 │ ├ admin.py
 │ ├ apps.py
 │ ├ models.py
 │ ├ tests.py
 │ ├ urls.py
 │ └ views.py
 │ 
 ├ project/
 │ ├ asgi.py
 │ ├ settings.py
 │ ├ urls.py
 │ └ wsgi.py
 │ 
 └ templates/
   └ blog/
     └ index.html

次に作成したファイルをコード書いていきます。

・project/settings.py
・project/urls.py
・blog/urls.py
・blog/views.py
・templates/blog/index.html

まずはproject/settings.pyにblogアプリを登録します。以下の設定を行います。

  • INSTALLED_APPS
  • TEMPLATES
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog', #これを追加
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            Path.joinpath(BASE_DIR, 'templates'), #これを追加
        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

project/urls.pyにblogアプリにルーティングしてきます。

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', include('blog.urls')),
    path('admin/', admin.site.urls),
]

blog/urls.pyにトップページをルーティングします。

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

blog/views.pyを作成します。

from django.shortcuts import render


def index(request):
    return render(request, 'blog/index.html')

最後はtemplates/blog/index.htmlは作成します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
</head>
<body>
    <h1>Hello World</h1>
</body>
</html>

コーディングが終わったらブラウザでlocalhost:8000にアクセスしてみましょう。

DjangoでTemplateを使用したHello World画面

2. ルーティングのやり方

画像準備中

3. データベースの設定とモデルの作成とマイグレーション

次にデータベースの設定を行います。

今回は使用するデータベースはSQLiteです。特にデータベースとしての設定は不要になります。

ただし今後のことを踏まえてどこを設定するべきかはレクチャーしますのでご安心ください。

今回はPost(投稿)テーブルを1つ作ってみます。テーブル定義は以下になります。

ここに定義を入れる

今回使用するファイルは以下です。

・project/settings.py
・blog/model.py

まずproject/settings.pyにデータベースを設定を確認しましょう。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}

次にblog/models.pyにデータベースを設定します。

from django.db import models


class Post(models.Model):
    id = models.AutoField(primary_key=True,
                          db_column='id')
    title = models.CharField(max_length=255,
                             null=False,
                             blank=False,
                             db_column='title')
    content = models.TextField(null=False,
                               blank=True,
                               db_column='content')
    create_at = models.DateTimeField(default=None,
                                     null=False,
                                     blank=False,
                                     db_column='create_at')
    update_at = models.DateTimeField(default=None,
                                     null=True,
                                     blank=True,
                                     db_column='update_at')

最後に作成したモデルからmigrateファイル(実施にデータベース定義するファイル)を作成し、データベースにPostテーブルを定義します。

python manage.py makemigrations
python manage.py migrate

この時にDjangoのAdmin機能に必要なデータベースも合わせて定義されます。以下のようにログが出力されるはずです。

# python manage.py makemigrations
Migrations for 'blog':
  blog/migrations/0001_initial.py
    - Create model Post

# python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying blog.0001_initial... OK
  Applying sessions.0001_initial... OK

一旦ここまででテーブルの作成が完了しました。

しかし実際に使ってはいないですし作成できたのかもわかりません。

なので次の章で作成したテーブルの中身を確認してみましょう。

4. superuserの作り方とAdmin管理画面での操作

前章で作成したテーブルが実際に作成されたことを確認するために、superuser(特権ユーザ)を作成してAdmin画面で確認してみましょう。

・blog/admin.py

superuserを作成するコマンドは以下になります。

python manage.py createsuperuser

ユーザの作成は以下のように行います。ユーザ名、メールアドレス、パスワードは任意の値を設定してください。

# python manage.py createsuperuser
ユーザー名 (leave blank to use 'root'): root
メールアドレス: root@root.com
Password: 
Password (again): 
Superuser created successfully.

最後にblog/admin.pyを設定します。

from django.contrib import admin
from .models import Post

admin.site.register(Post)

ユーザが作成したらブラウザで localhost:8000/admin にアクセスしてみましょう。

Django管理サイトのログイン画面

Blog→Postと遷移することができ、無事Postテーブルが作成できたことを確認できました。

Django管理サイトのログイン画面

5. データベースの情報をViewに表示する

ここからは本格的なdjangoのMVTを活用していきたいと思います。

ここではPostテーブルに格納されているデータを表示するアプリを作成してみたいと思います。

まず初めにPostテーブルに3件のデータを入れたいと思います。

以下のPostの追加を選択します。

Django管理サイトからPostを追加

テストデータを追加していきます。

Django管理サイトでPostテーブルにデータを追加

同様の手順で以下のように3件データを用意しましょう。

Django管理サイトで

ここまで出来たら表示するデータの準備は完了しました。

次にPostテーブルデータを表示するためのアプリをコーディングしていきます。

・blog/urls.py
・blog/views.py
・templates/blog/index.html ※既存のファイルを修正
・templates/blog/detail.html

まずは新しくルーティングをするためにblog/urls.py修正します。

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('detail/<int:pk>', views.detail, name='detail'),
]

次にPostテーブルに登録されている記事の一覧と記事の詳細を表示するページをコーディングします。

なお、記事一覧は既に作成してある、indexファンクションを修正します。

from django.shortcuts import render
from .models import Post


def index(request):
    posts = Post.objects.all()
    ctx = {
        'posts': posts,
    }
    return render(request, 'blog/index.html', ctx)


def detail(request, pk):
    post = Post.objects.get(id=pk)
    ctx = {
        'post': post
    }
    return render(request, 'blog/detail.html', ctx)

次にテンプレートを作成します。

初めにtemplates/blog/index.htmlを修正します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
</head>
<body>
    <h1>Django Sample Blog</h1>
    <div>
        <ul>
            {% for post in posts %}
            <li>
                <a href="{% url 'detail' post.pk %}">
                    {{ post.title }}
                </a>
            </li>
            {% endfor %}
        </ul>
    </div>
</body>
</html>

次に初めにtemplates/blog/detail.htmlを作成します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
</head>
<body>
    <div>
        <h1>Django Sample Blog</h1>
        <div>
            <h2>{{ post.title }}</h2>
            <p>{{ post.content }}</p>
            <p>{{ post.create_at }}</p>
            <p>{{ post.update_at }}</p>
            <a href="/">戻る</a>
        </div>
    </div>
</body>
</html>

ここまで出来たら動作を確認してみましょう。

localhost:8000にアクセスしてみますと以下の画面が表示されているはずです。

ブログアプリのトップページ

サンプルデータのリンクを確認してみましょう。すると以下ように個別ベージを表示することができました。

DjangoサンプルBlogの個別ページ

ここまで出来ればデータベースの情報を表示することができました。

6. スタイル(CSS)を追加する

ブログの記事管理を行うことはできましたが、これだと見た目がシンプル過ぎます。

この章でスタイルを追加して見栄えを良くしていきます。

今回は最もシンプルなCSSフレームワークのBootstrap5を利用したいと思います。

利用はとてもシンプルでheadタグにCSSのリンクを設定していきます。

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">

CSSを適用したtemplates/blog/index.htmlは以下になります。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1>Django Sample Blog</h1>
        <ul class="list-group">
            {% for post in posts %}
            <li class="list-group-item list-group-item-action">
                <a href="{% url 'detail' post.pk %}" class="d-block text-reset text-decoration-none">
                    {{ post.title }}
                </a>
            </li>
            {% endfor %}
        </ul>
    </div>
</body>
</html>

templates/blog/detail.html にも設定していきます。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1>Django Sample Blog</h1>
        <div class="border p-3">
            <h2 class="fw-bold">{{ post.title }}</h2>
            <p>{{ post.content }}</p>
            <p>{{ post.create_at }}</p>
            <p>{{ post.update_at }}</p>
            <a href="/">戻る</a>
        </div>
    </div>
</body>
</html>

それではスタイルが適用されたか確認してみましょう。

トップページは以下のような画面になります。

Bootstrap5で詳細を整えたトップページ

次に詳細ページを確認してみます。

Bootstrap5で詳細を整えた詳細ページ

このようにDjangoでも通常のHTMLと同様にCSSを利用することができます。

※ 今回はDjangoでスタイルを追加する方法にフォーカスしているので必要最低限で実施しています。

7. Formの作成とデータの登録

次に管理画面からではなくデータの登録する機能を追加します。

新規にforms.pyをblogアプリディレクト配下に作成します。

root/
 ├ blog/
 │ ├ migrations/
 │ │ └ __init__.py
 │ ├ __init__.py
 │ ├ admin.py
 │ ├ apps.py
 │ ├ forms.py # これを新規追加
 │ ├ models.py
 │ ├ tests.py
 │ ├ urls.py
 │ └ views.py
 │ 

From機能とはHTMLのformタグからリクエストを送る機能になります。

DjangoではForm機能を使うことで簡単かつ高品質のFormを作成することができます。

データ登録を作成するために必要なファイルは以下になります。

・blog/forms.py
・blog/urls.py
・blog/views.py
・templates/blog/index.html ※既存のファイルを修正
・templates/blog/create.html

まずはFormを作成します。

from django import forms
from .models import Post


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = [
            'title',
            'content',
        ]

次にblog/urls.pyにデータを登録するためのルーティングを追加します。

from django.urls import path	from django.urls import path
from . import views	from . import views

app_name = 'cms'	app_name = 'cms'

urlpatterns = [	urlpatterns = [
    path('', views.index, name='index'),
    path('detail/<int:pk>', views.detail, name='detail'),	 
    path('create/', views.create, name='create'), # ここを追加
]

次にblog/views.pyにcreateファンクションを追加します。

from django.shortcuts import render, redirect #ここを追加
from django.utils import timezone #ここを追加
from .models import Post
from .forms import PostForm #ここを追加

  
def index(request):
    posts = Post.objects.all()
    ctx = {
        'posts': posts,
    }
    return render(request, 'blog/index.html', ctx)

def detail(request, pk):
    post = Post.objects.get(id=pk)
    ctx = {
        'post': post
    }
    return render(request, 'blog/detail.html', ctx)


# ここから新規に追加
def create(request):
    ctx = {}
    if request.method == 'GET':
        ctx['form'] = PostForm
        return render(request, 'blog/create.html', ctx)
    elif request.method == 'POST':
        Post.objects.create(title=request.POST.get('title', None),
                            content=request.POST.get('content', None),
                            create_at=timezone.now())
        return redirect(to='index')

templates/blog/index.htmlに作成リンクを追加します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1>Django Sample Blog</h1>
        <ul class="list-group">
            {% for post in posts %}
            <li class="list-group-item list-group-item-action">
                <a href="{% url 'detail' post.pk %}" class="d-block text-reset text-decoration-none">
                    {{ post.title }}
                </a>
            </li>
            {% endfor %}
        </ul>
        <div class="d-flex mt-2">
            <a href="{% url 'create' %}" class="btn btn-primary">作成</a>
        </div>
    </div>
</body>
</html>

作成用のテンプレートをtemplates/blog/create.htmlを作成します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1>Django Sample Blog</h1>
        <form method="POST" action="{% url 'create' %}">
            {% csrf_token %}
            <table class="table">
                {{ form.as_table }}
            </table>
            <div class="d-flex justify-content-center">
                <input type="submit" class="btn btn-primary" value="作成">
            </div>
        </form>
    </div>
</body>
</html>

では記事を作成してみたいと思います。作成ボタンを押します。

作成ボタン付きトップページ

必要な情報を入力して作成ボタンを押します。

作成画面

作成されるとトップページに遷移します。

記事作成後のトップページ

データ作成のためのフォームの作成は完了です。

8. Formからデータの修正と削除

Postデータの修正と削除を行えるようにして、より本格的なBlogアプリにしていきましょう。

データ作成と同様にFormと使うことで修正と削除を簡単に行うことができます。

・blog/views.py
・blog/urls.py
・templates/blog/index.html ※既存のファイルを修正
・templates/blog/modify.html
・templates/blog/delete.html

次に修正用と削除用のファンクションを追加します。

from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from .models import Post
from .forms import CreateViewForm


def index(request):
    posts = Post.objects.all()
    ctx = {
        'posts': posts,
    }
    return render(request, 'blog/index.html', ctx)


def detail(request, pk):
    post = Post.objects.get(id=pk)
    ctx = {
        'post': post
    }
    return render(request, 'blog/detail.html', ctx)


def create(request):
    ctx = {}
    if request.method == 'GET':
        ctx['form'] = PostForm
        return render(request, 'blog/create.html', ctx)
    elif request.method == 'POST':
        Post.objects.create(title=request.POST.get('title', None),
                            content=request.POST.get('content', None),
                            create_at=timezone.now())
        return redirect(to='index')


def modify(request, pk):
    ctx = {}
    if request.method == 'GET':
        post = get_object_or_404(Post, id=pk)
        ctx['form'] = ModifyViewForm(instance=post)
        return render(request, 'blog/modify.html', ctx)
    if request.method == 'POST':
        post = Post(id=pk,
                    title=request.POST.get('title'),
                    content=request.POST.get('content'),
                    update_at=timezone.now())
        post.save()
        return redirect(to='detail', pk=pk)


def delete(request, pk):
    ctx = {}
    if request.method == 'GET':
        instance = get_object_or_404(Post, id=pk)
        ctx['instance'] = instance
        return render(request, 'blog/delete.html', ctx)
    if request.method == 'POST':
        Post.objects.filter(id=pk).delete()
        return redirect(to='index')

次にurls.pyで修正用と削除用のURLディスパッチャーと追加します。

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('detail/<int:pk>', views.detail, name='detail'),
    path('create/', views.create, name='create'),
    path('modify/<int:pk>', views.modify, name='modify'),
    path('delete/<int:pk>', views.delete, name='delete'),
]

修正用ボタンと削除ボタンをテンプレートを追加します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1 class="py-2">Django Sample Blog</h1>
        <div class="border p-3">
            <h2 class="fw-bold">{{ post.title }}</h2>
            <p>{{ post.content }}</p>
            <p>{{ post.create_at }}</p>
            <p>{{ post.update_at }}</p>
            <a href="/">戻る</a>
        </div>
        <!-- ここを追加 --!>
        <div class="d-flex justify-content-start mt-2">
            <a href="{% url 'modify' post.pk %}" class="btn btn-primary me-2">修正</a>
            <a href="{% url 'delete' post.pk %}" class="btn btn-secondary me-2">削除</a>
        </div>
    </div>
</body>
</html>

修正用テンプレートとしてtemplates/blog/modify.htmlを作成します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1 class="py-2">Django Sample Blog</h1>
        <form method="POST" action="{% url 'create' %}">
            {% csrf_token %}
            <table class="table">
                {{ form.as_table }}
            </table>
            <div class="d-flex justify-content-center">
                <input type="submit" class="btn btn-primary" value="作成">
            </div>
        </form>
    </div>
</body>
</html>

最後に削除用テンプレートを作成します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1 class="py-2">Django Sample Blog</h1>
        <div class="border p-3">
            <h2>{{ instance.title }}</h2>
            <p>{{ instance.content }}</p>
            <p>{{ instance.create_at }}</p>
        </div>
        <p class="text-danger mt-2">上記の記事を本当に削除しますか?</p>
        <form method="POST" action="{% url 'delete' instance.pk %}" class="d-flex justify-content-start mt-2">
            {% csrf_token %}
            <input type="submit" class="btn btn-primary me-2" value="削除">
            <a href="{% url 'detail' instance.pk %}" class="btn btn-secondary">戻る</a>
            <input type="hidden" value="{{ post.pk }}">
        </form>
    </div>
</body>
</html>

では確認してみましょう

詳細ページに修正ボタンとと削除ボタンが追加されました。

修正ボタンと削除ボタンが追加された詳細ページ

修正ボタンを選択すると修正ができます

修正ページ

また削除ボタンを選択すると削除ページが利用できます。

削除ページ

これで記事の修正と削除を行うことができました。

8. 画像のアップロードできるFormを作成

最後に画像のアップロードできるようにしたいと思います。

画像のアップロードできるようにするために多くの設定が必要になります。

初めにPython画像処理ライブラリである「Pillow」を導入します。

pip install Pillow

ではコーディングしていきます。対象は以下のファイルになります。

・project/settings.py
・project/urls.py
・blog/models.py
・blog/forms.py
・templates/blog/create.html
・templates/blog/modify.html
・templates/blog/detail.html

まずはproject/settings.pyを修正していきます。

# これを追記
MEDIA_ROOT = Path.joinpath(BASE_DIR, 'media')
MEDIA_URL = '/media/'

project/urls.pyに画像保存用URL設定を入れていきます。

from django.contrib import admin
from django.urls import path, include
from django.conf import settings #これを追加
from django.conf.urls.static import static #これを追加

urlpatterns = [
    path('', include('blog.urls')),
    path('admin/', admin.site.urls),
]

urlpatterns = urlpatterns + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) #これを追加

Postモデルにimageカラムを追加します。

class Post(models.Model):
    id = models.AutoField(primary_key=True,
                          db_column='id')
    title = models.CharField(max_length=255,
                             null=False,
                             blank=False,
                             db_column='title')
    content = models.TextField(null=False,
                               blank=True,
                               db_column='content')
    # ここを修正
    image = models.ImageField(upload_to='images/',
                              null=True,
                              blank=True,
                              db_column='image')
    create_at = models.DateTimeField(default=timezone.now,
                                     null=False,
                                     blank=False,
                                     db_column='create_at')
    update_at = models.DateTimeField(default=None,
                                     null=True,
                                     blank=True,
                                     db_column='update_at')

完了したら忘れずにマイグレーションを行います。

python manage.py makemigrations
python manage.py migrate

マイグレーションのログは以下のようになります。

# python manage.py makemigrations
Migrations for 'blog':
  blog/migrations/0002_post_image.py
    - Add field image to post

# python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
  Applying blog.0002_post_image... OK

次にFormsでimageを追加します。

from django import forms
from .models import Post


class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = [
            'title',
            'content',
            'image', #ここを追記
        ]

blog/views.pyでファイルをアップロードできるように設定します。

from django.shortcuts import render, redirect, get_object_or_404
from django.utils import timezone
from .models import Post
from .forms import PostForm


def index(request):
    posts = Post.objects.all()
    ctx = {
        'posts': posts,
    }
    return render(request, 'blog/index.html', ctx)


def detail(request, pk):
    post = Post.objects.get(id=pk)
    ctx = {
        'post': post
    }
    return render(request, 'blog/detail.html', ctx)


def create(request):
    ctx = {}
    if request.method == 'GET':
        ctx['form'] = PostForm
        return render(request, 'blog/create.html', ctx)
    elif request.method == 'POST':
        Post.objects.create(title=request.POST.get('title', None),
                            content=request.POST.get('content', None),
                            image=request.FILES['image'], # ここを追記
                            create_at=timezone.now())
        return redirect(to='index')


def modify(request, pk):
    ctx = {}
    if request.method == 'GET':
        post = get_object_or_404(Post, id=pk)
        ctx['form'] = PostForm(instance=post)
        return render(request, 'blog/modify.html', ctx)
    if request.method == 'POST':
        post = Post(id=pk,
                    title=request.POST.get('title'),
                    content=request.POST.get('content'),
                    image=request.FILES['image'], # ここを追記
                    update_at=timezone.now())
        post.save()
        return redirect(to='detail', pk=pk)


def delete(request, pk):
    ctx = {}
    if request.method == 'GET':
        instance = get_object_or_404(Post, id=pk)
        ctx['instance'] = instance
        return render(request, 'blog/delete.html', ctx)
    if request.method == 'POST':
        Post.objects.filter(id=pk).delete()
        return redirect(to='index')

最後にテンプレートファイルを修正していきます。

まずはtemplate/blog/create.htmlを修正します。formタグに「enctype="multipart/form-data"」を設定します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1 class="py-2">Django Sample Blog</h1>
        <form method="POST" action="{% url 'create' %}" enctype="multipart/form-data">
            {% csrf_token %}
            <table class="table">
                {{ form.as_table }}
            </table>
            <div class="d-flex justify-content-center">
                <input type="submit" class="btn btn-primary" value="作成">
            </div>
        </form>
    </div>
</body>
</html>

template/blog/modify.htmlを修正します。formタグに「enctype="multipart/form-data"」を設定します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1 class="py-2">Django Sample Blog</h1>
        <form method="POST" action="{% url 'modify' form.instance.pk %}" enctype="multipart/form-data">
            {% csrf_token %}
            <table class="table">
                {{ form.as_table }}
            </table>
            <div class="d-flex justify-content-center">
                <input type="submit" class="btn btn-primary" value="修正">
            </div>
        </form>
    </div>
</body>
</html>

表示するテンプレートを修正します。

<!doctype html>
<html lang="jp">
<head>
    <meta charset="utf-8">
    <title>Django Sample blog</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <h1 class="py-2">Django Sample Blog</h1>
        <div class="border p-3">
            <h2 class="fw-bold">{{ post.title }}</h2>
            <p>{{ post.content }}</p>
            <img src="{{ post.image.url }}" class="img-fluid">
            <p>{{ post.create_at }}</p>
            <p>{{ post.update_at }}</p>
            <a href="/">戻る</a>
        </div>
        <div class="d-flex justify-content-start mt-2">
            <a href="{% url 'modify' post.pk %}" class="btn btn-primary me-2">修正</a>
            <a href="{% url 'delete' post.pk %}" class="btn btn-secondary me-2">削除</a>
        </div>
    </div>
</body>
</html>

作成画面・修正画面共の画像をアップロードできるようになったと思います。※ 画像は作成画面

作成画面での画像のアップロード

データが登録されると詳細画面で画像が表示できたと思います。

画像がアップロードされた詳細画面

アップロードしたファイルは画像の通り、media/imageディレクトリの配下にアップロードされます。

media/imagesにアップロードされた画像ファイル

これで全てのサンプルプログラムが終わりです。

サンプルのプログラムは以下のリンクに上がっています。

Github:django-sample-blog

Djangoのライブラリを利用して必要機能を即利用

Djangoの最大メリットとして「ライブラリが充実している」点があげられます。

Djang+ライブラリで開発コスト大幅に減らすことができます。

以下に特によく使うライブラリを一例を紹介します。

  • Django REST framework:DjangoでRestFrameworkを作成できる。APIドキュメントの自動生成がされる。
  • django-allauth:認証機能の拡張や認証プロバイダー(SNSログインなどの外部認証を使う)ができる
  • Django Channels:websocket通信が実装でき、チャットやゲームなどに利用できる
  • Django Debug Toolbar:Djangoのデバッカーツール
  • Wagtail:DjangoのCMS。WordPressのような使い方が可能

「Django+やりたいこと」で検索すると大体ライブラリは出てきますので試してみてください。

またDjango Packagesというよく使う機能とライブラリがまとまったサイトもありますので確認してみてください。

参考:Django Packages

公式ドキュメントとDjangoの読み方

Djangoは公式ドキュメントが豊富に揃っています。

ブログ記事でキャッチアップをすることは推奨しますが最後はきちんと公式マニュアルを確認するようにしましょう。

日本語化の方法

また日本語化整っているので英語が苦手な人でも読むことができます。

Djangoの公式ドキュメントの右下で「ja」を選択すればOKです。

すると以下のように日本語化されます。ただし一部日本語化されていないです。

マニュアルのしおり

マニュアルが整備されているがどこに何が書かれているのか?が入門者にはわかりづらいと思います。

なので公式マニュアルのしおりを作成しています。

目次説明
モデル層モデルとデータベース全般の内容が記載されています。
ビュー層ユーザーのリクエストとレスポンスの内容が記載されています。
テンプレート層テンプレートに関する内容が記載されています。
フォーム層データをPOSTするときのフォーム情報についてき記載されています。
開発プロセス開発に役立つツールやテストについて記載されています。
管理インタフェースDjangoデフォルトの管理機能について記載されています。
セキュリティDjangoのセキュリティ機能について記載されています。
国際化と地域化タイムゾーンや表示する言語などについて記載されています。初心者ではほぼ不要になります。
パフォーマンスと最適化パフォーマンス測定について記載されています。初心者ではほぼ不要です。
地理情報フレームワークGISという特別なデータベースを使う時に使用します。初心者では不要です。
Common web application toolsキャッシュやセッション管理など一般的なWebサービスで必要な機能がDjangoではどのように扱うのかについて記載されています。
その他の主要機能文字通りその他です。
オープンソースプロジェクトとしての DjangoDjangoのOSSコミュニティについて記載されています。

まとめ

以上でDjangoの超入門ドキュメントが終わりです。

Djangoは強力なWebフレームワークで海外では多くのサイトで利用されていますが、日本では利用実績が少なく(または観測できるほど大きなサービスになっていない?)非常に残念なためこちらの記事を作成しました。

これからより高度な内容も発信していきたいと思いますのでよろしければブックマークをお願いします。

疑問点がありましたら問い合わせからよろしくお願い致します。

よかったらシェアしてね!
目次
閉じる