0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Django入門:環境構築からCRUD実装まで、MVTモデルの図解付きで徹底解説

0
Last updated at Posted at 2026-04-26

手順

1. 環境設定

1.1 Python 仮想環境を用意する

ここでは,pipenvを利用する.

pipenvをインストール
python -m pip install pipenv

1.2 Djangoのインストール

Django のインストール
python -m pip install Django

2. プロジェクトの作成

以下のコマンドで,プロジェクトが立ち上がる.

新規プロジェクトの作成
python -m django startproject MemoPad

以下のようなプロジェクトが立ち上がる

treeコマンドの実行
.
├── manage.py
└── MemoPad
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

仮想環境を作成する

仮想環境の作成
cd MemoPad
pipenv --python 3.12

Pipfileが生成される.

仮想環境の立ち上げ
pipenv shell
Djangoインストール
pipenv install django

とりあえずサーバーが起動できる

出来上がったプロジェクトにcdして以下のコマンドを実行する

サーバーを立ち上げる
python manage.py runserver

http://localhost:8000/ にアクセスする.
image.png

3. サブシステムを作る

ここでサブシステムとは,システム全体(プロジェクト)を構成する 「個別の機能単位(アプリ)」 のことを指しています。

helloというサブシステムを作成
python manage.py startapp memo 

これを実行すると,root ディレクトリに hello ディレクトリが作成されます.

treeコマンド実行
.
├── manage.py
├── memo
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── MemoPad
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── Pipfile
└── Pipfile.lock

[間章] MVC / MVTについて

Webアプリケーションはブラウザ、サーバー、アプリケーション、データベースのやり取りで構成されます 。この「Application」の中身を整理する設計図がMVCやMVTです。

MVC とは

ソフトウェアの設計図(デザインパターン)の一種で、「Model(モデル)」「View(ビュー)」「Controller(コントローラー)」 の3つの役割にコードを切り分けて整理する考え方のことです。

ひとまとまりの大きなプログラムを作ろうとすると、中身が複雑になって「どこに何が書いてあるか分からない(スパゲッティコード)」状態になりがちです。それを防ぐために、役割ごとに「担当者」を分けるのがMVCの目的です。

3つの役割のイメージ

レストランの運営に例えると分かりやすいです。

  • Model (モデル):データ担当(厨房)
    システムで扱うデータそのものと、そのデータをどう処理するかというルールを管理します。
    データベースとのやり取りを行い、「食材(データ)」を「料理(処理結果)」に変える役割です。

  • View (ビュー):見た目担当(客席・メニュー)
    ユーザーに表示される画面のことです。
    モデルから送られてきたデータを、見やすいHTMLやグラフなどの形に整えてユーザーに提示します。

  • Controller (コントローラー):司令塔(ウェイター)
    ユーザーからの入力(リクエスト)を受け取り、モデルやビューに指示を出します。
    「お客様(ユーザー)がこの料理を注文したから、厨房(モデル)に作らせて、出来上がったらお皿(ビュー)に盛り付けて運ぼう」という全体の交通整理を行います 。

MVT とは

MVTとは、Djangoが採用している独自の設計パターンのことで、 「Model(モデル)」「View(ビュー)」「Template(テンプレート)」 の頭文字を取ったものです。
概念としては先ほど説明したMVCとほぼ同じですが、 「役割の呼び名」 がDjango特有のものになっています。

3つの役割のイメージ

  • Model (モデル):データ担当
    役割: データベースの構造(スキーマ)を定義し、データの保存や取得を行います 。
    料理で言えば「材料」や「レシピ」を管理する厨房のような存在です。

  • View (ビュー):ロジック担当(司令塔)
    役割: ユーザーからのリクエストを受け取り、Modelからデータを取ってきて、どのTemplateを使うか決める「制御(ロジック)」を行います 。
    ここが混乱の元!: 一般的なMVCではこれをControllerと呼びますが、DjangoではViewと呼びます 。
    ウェイターのように全体の流れを仕切る司令塔です。

  • Template (テンプレート):見た目担当
    役割: ユーザーに表示するHTMLなどの画面レイアウトです 。
    一般的なMVCとの違い: MVCではこれをViewと呼びますが、DjangoではTemplateと呼びます。
    盛り付けられた「お皿」そのものです。

MVCとMVTの違いまとめ

要素 MVCでの呼び名 Django(MVT)での呼び名 役割
データ Model Model データベースとのやり取りやデータの定義 。
見た目 View Template HTMLのレイアウトや表示方法 。
制御 Controller View リクエストを受け取り、Modelからデータを取ってTemplateに渡す「司令塔」 。

4. /memo にアクセスされた時の挙動を定義する

4.1 view を記述する

まず,/memoにアクセスされた時,何を表示するか定義する

  • 編集ファイル:/memo/views.py
  • /memoにアクセスした時,Hello, world. You're at the hello's index.と表示するようにする
views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("Hello, world. You're at the memo's index.")

4.2 プロジェクト全体のURL設定に memo を追加する

次に、プロジェクト全体を管理するURL設定ファイルに、「memo/ というURLが来たら hello アプリに任せる」という指示を追加します。

  • 編集ファイル: MemoPad/urls.py
  • 記述内容: include をインポートし、urlpatterns に1行追加します。
MemoPad / urls.py
from django.contrib import admin
from django.urls import path, include # include を追加

urlpatterns = [
   path('memo/', include('memo.urls')), # この行を追加
   path('admin/', admin.site.urls),
]

path('admin/', ...): admin/ で始まるURLが来た場合に、Djangoが標準で提供している管理画面機能を呼び出すように指定しています

include とは何か

include は、他のURL設定ファイルを再利用したり、読み込んだりするための関数です 。

  • 役割: プロジェクト全体の urls.py ですべてを管理すると、コードが膨大になり複雑になってしまいます。そこで include を使うことで、「memo/ に関する詳細なURL設定は、memo アプリの中にある urls.py を参照してください」という具合に、各アプリへ管理を委ねることができます 。
  • メリット: これにより、アプリ(サブシステム)ごとの独立性が高まり、別のプロジェクトへアプリを移植しやすくなるなど、管理が効率的になります 。

4.3 memoアプリ専用に設定ファイルを作成する

  • ファイル作成: memoフォルダに,urls.pyを新規作成する
  • 記述内容: 作成したファイルに以下を書き込みます。
memo / urls.py
from django.urls import path
from . import views

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

includeによって,/memo以降のサブページのルーティングはmemo/urls.pyに移譲されました.
このファイルで,/memoにアクセスした時の挙動がviewsのindex関数によって定義されるということが述べられています.

4.4 動作確認

すべて保存したら、ターミナルでサーバーを起動します。

Bash
python manage.py runserver

ブラウザで http://127.0.0.1:8000/hello/ にアクセスしてみてください。「Hello, world...」という文字が表示されれば成功です!

5. データベースの設定

データベース(SQLite)を活用したメモ帳システムを構築するのがゴールです 。

5.1 プロジェクトへの登録(Settings の編集)

まず、作成した memo アプリをプロジェクト全体に認識させます。

  • 編集ファイル: MemoPad / settings.py
  • 作業: INSTALLED_APPS というリストを探し、その一番上に以下の1行を追加してください 。
MemoPad / setting.py
INSTALLED_APPS = [
    'memo.apps.MemoConfig',  # この行を追加
    'django.contrib.admin',
    ...
]

settings.py を編集する理由

settings.pyを編集し,memoアプリをプロジェクト全体に認識させることで,Djangoの強力な機能(特にデータベース)をフル活用することができるようになります.

  1. データベース(Model)と連携するため.
    • Djangoには、プログラムで書いた設定を実際のデータベースの形に変換する「マイグレーション」という便利な機能があります。
    • この機能は、settings.py に登録されているアプリの models.py しか読み取ってくれません。登録していないと、せっかく書いたメモ帳のデータ構造をデータベースに反映できなくなります。
  2. テンプレート(HTMLファイル)を見つけるため
    今後は,HTMLファイル(テンプレート)を使って画面を作ることになります。
    • Djangoは、「INSTALLED_APPS に登録されているアプリのフォルダの中」を自動的に探しに行って、HTMLファイルを見つけ出します。
    • 登録がないと、画面を表示しようとした時に「テンプレートが見つかりません」というエラーになってしまいます。
  3. アプリケーションとしての「正攻法」
    • 本格的なサブシステムとして Django の管理画面(admin)やセキュリティ機能、独自のコマンドなどを使うためには、この登録作業が必須になります。

5.2 モデルの定義(データの設計図を作る)

まずは、一つの「メモ」がどのような情報(テキスト、作成日時など)を持つかを定義します。

  • 編集ファイル: memo/models.py
  • 記述内容: 以下のコードを追記してください。
memo / models.py
from django.db import models
from django.utils import timezone
from datetime import datetime

# Memo Table
class Memo(models.Model):
    class Meta:
        verbose_name = 'Memo Table'
        verbose_name_plural = 'Memos Table'
        db_table = 'memo'
    
    content = models.CharField(verbose_name='メモ', max_length=100, default="", blank=True, null=True)
    created_at = models.DateTimeField(verbose_name='作成日時', default=timezone.now)

    def __str__(self):
        return self.content + '(' + datetime.strftime(self.created_at, '%Y/%m/%d %H:%M:%S') + ')'

5.3 マイグレーション(データベースに反映する)

プログラムに書いた設計図を、実際のデータベース(SQLite)のテーブルとして作成します。これには2つのコマンドを使います 。

マイグレーションとは Migration(マイグレーション)は、日本語で「移動」「移住」「移転」「移行」を意味します。人や動物の移動、あるいはシステムやデータを新しい環境へ移行する(マイグレーション)プロセスを指す言葉として、IT分野や社会科学で広く使われます。
ここでは,Pythonプログラムで書いた「データの定義(Model)」を、実際のデータベース(SQLiteなど)の「テーブル構造」に反映させるための橋渡し役を担っています 。

5.3.1 設計図の作成(makemigrations):

「モデルが変更されたので、データベースをこう変えるべきだ」という指示書(マイグレーションファイル)を生成します。

マイグレーションファイルの生成
python manage.py makemigrations memo

5.3.2 変更の実行(migrate)

指示書に従って、実際にデータベースの中に memo 用のテーブルを作成します。

memo 用テーブルの作成
python manage.py migrate

5.3.3 管理者ユーザーの作成

マイグレーションが成功したら、データベースを操作するための特権ユーザーを作成します 。

特権ユーザーの作成
python manage.py createsuperuser

実行するとユーザー名、メールアドレス、パスワードを順に聞かれます。パスワード入力時は画面に文字が表示されませんが、そのまま入力してエンターキーを押してください 。

5.3.4 マイグレーションの状態を確認する

マイグレーションの状態を確認する
python manage.py showmigrations

5.4 フォームの作成

ユーザーがブラウザからメモを入力するための「入力欄」を定義します.

5.4.1 新しいフォルダの作成

以下の通りにフォルダとファイルを作成してください 。

  1. memo フォルダの中に、forms という名前のフォルダを作成します 。
  2. forms フォルダの中に、さらに memo という名前のフォルダを作成します 。
  3. 一番奥の memo フォルダの中に、forms.py というファイルを作成します 。

5.4.2 forms.py の記述

今作成した memo/forms/memo/forms.py に書き込みます 。

memo / forms / memo / forms.py
from django import forms
from memo.models import Memo # 先ほど作ったModelをインポート

class MemoForm(forms.ModelForm): # DjangoのModelForm機能を継承
    class Meta:
        model = Memo
        fields = ['id', 'content', 'created_at'] # 扱う項目を指定 

    # メモ本文の入力欄設定
    content = forms.CharField(
        label="Content",
        max_length=30,
        required=True,
        widget=forms.TextInput(attrs={'size': '58'}), # 入力枠の長さを指定 
    )

    # 作成日時の入力欄設定
    created_at = forms.DateField(
        label='Created at',
        required=False,
        input_formats=['%Y-%m-%d'],
        widget=forms.TextInput(attrs={'size': '12'}), # 日付用の枠サイズ 
    )

5.4.3 Views の階層化

フォームができたら、次はいよいよメモを一覧表示したり保存したりする「ロジック」を書く Views の準備です。

  1. memo フォルダの中に、views というフォルダを「Python Package」として作成します 。
    • memoフォルダの中にviewsというフォルダを作成.
    • そのフォルダの中に,init.pyという空のファイルを作成する.
  2. views フォルダの中に、さらに memo というフォルダを「Python Package」として作成します 。
  3. もともと memo フォルダの直下にあった views.py を、この一番奥の views フォルダの中(memo/views/memo/)へ移動させてください 。

5.5 テンプレートの作成

次は「各 View の中身の実装」と「Templates(画面)の作成」に進みます。少し分量が多いですが、ここを乗り越えればメモ帳が動くようになります。

Django におけるテンプレートとは

Djangoにおけるテンプレートとは、 「ブラウザに表示する画面の雛形(HTMLファイル)」 のことです.

  • 役割: ほぼ通常のHTMLファイルですが、中に「テンプレート言語」という独自の命令を埋め込むことができます 。これにより、プログラム(View)から送られてきたデータを動的に画面にはめ込むことが可能です 。
  • 特徴的な記法: {{ my_message }}(変数の表示)や {% if ... %}(条件分岐)といった記号を使って、見た目とロジックを組み合わせて記述します 。
  • 構成: base.html(共通の枠組み)を他のファイルが {% extends %} で継承して使い回すことで、効率的にデザインを管理できる仕組みになっています 。

5.5.1. CRUD(一覧・作成・更新・削除)のロジックを書く

一番奥の階層にある memo/views/memo/views.py を開き、以下のコードを記述してください。ここでは、Django の「汎用ビュー(Generic View)」という便利な機能を使って、最小限の記述でデータベース操作を実現します。

memo / views / memo / views.py
from django.shortcuts import render, redirect
from django.views import generic
from django.urls import reverse_lazy
from django.utils import timezone
from memo.models import Memo
from memo.forms.memo.forms import MemoForm

# メモ一覧の表示
class MemoListView(generic.ListView):
    model = Memo
    queryset = Memo.objects.order_by('-created_at') # 新しい順に並べる
    paginate_by = 10 # 1ページに10件表示
    template_name = "memo/list_memo.html"
    success_url = reverse_lazy('home')

# メモの新規作成
class MemoCreateView(generic.CreateView):
    model = Memo
    form_class = MemoForm
    template_name = "memo/memo_form.html"
    success_url = reverse_lazy('memo:list_memo')
    
    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.created_at = timezone.now() # 現在時刻をセット
        self.object.save()
        return redirect('memo:list_memo')

# メモの編集
class MemoUpdateView(generic.UpdateView):
    model = Memo
    form_class = MemoForm
    template_name = "memo/memo_form.html"
    success_url = reverse_lazy('memo:list_memo')
    
    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.save()
        return redirect('memo:list_memo')

# メモの削除
class MemoDeleteView(generic.DeleteView):
    model = Memo
    success_url = reverse_lazy('memo:list_memo')
    
    def get(self, request, *args, **kwargs):
        self.object = Memo.objects.get(pk=kwargs['pk'])
        self.object.delete()
        return redirect('memo:list_memo')

5.5.2 ホーム画面の View を書く

次に、一階層上の memo/views/views.py を開き、スライド53枚目の内容に書き換えます。これは「サイトのトップページ」を表示するためのものです。

memo / views / views.py
from django.shortcuts import render
from django.views import generic

class Home(generic.TemplateView):
    template_name = 'home.html'
    
    def get(self, request, *args, **kwargs):
        context = super(Home, self).get_context_data()
        context.update({'my_message': 'Welcome to my site'}) # 画面に渡すデータ
        return render(request, 'home.html', context)

5.5.3 Templates(HTMLファイル)の作成

画面のパーツを作成します。 プロジェクトのルートディレクトリ(manage.py がある場所) に templates フォルダを作成し、その中に以下のファイルを配置してください。

  1. templates/ 直下
    • base.html: 全画面共通の枠組み(ヘッダーなど)。
    • home.html: トップページ。
  2. templates/memo/ フォルダ(新しく作成)の中
    • list_memo.html: メモ一覧画面。
    • memo_form.html: 作成・編集用フォーム画面。
base.html
<!doctype html>
{# Project: MwmoPad! (Hello World!) #}
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>{% block title %}{% endblock %}</title>
    {# --- css --- #}
    <meta http-equiv="Content-Type" content="text/css" />
    <style type="text/css">
      {% block extra_css %}{% endblock %}
    </style>
    <script language="javascript" type="text/javascript">
      {% block extra_javascript %}{% endblock %}
    </script>
  </head>

  <body>
    {% block header %}
    <div class="align-items-center bg-white border-bottom">
      <h5><a href="{% url 'home' %}">Hello World</a></h5>
    </div>
    {% endblock %}
    <div class="container">
      {% block content %}{% endblock %} {% block pagination_footer %}{% endblock%}
    </div>
    {# --- js --- #} {% block extra_js %}{% endblock %}
  </body>
</html>
home.html
{# Project: MemoPad #} 
{# HOME #} 
{% extends "base.html" %} 
{% block title %}MemoPad {% endblock %} 
{% block content %}
<br />
<div class="container">
  <!-- Content -->
  <h3>Hello World!</h3>
  {{ my_message }}
  <br />
</div>
{% endblock %}
list_memo.html
{# Project: MemoPad #} {# List of Memo #} {% extends "base.html" %} {% block title %}List of Memo - MemoPad!{% endblock title %} {% block content %}
<br />
<div class="container">
  <!-- Content -->
  <h3>Listing of Memos</h3>
  {% if object_list|length == 0 %}
  <p>No Memo Found</p>
  {% else %}
  <table class="table table-striped table-bordered">
    <tr>
      <th style="width: 40%">Memo</th>
      <th style="width: 30%">Date</th>
      <th>Edit</th>
      <th>Remove</th>
    </tr>
    <tbody>
      {% for memo in object_list %}
      <tr>
        <td>{{ memo.content }}</td>
        <td>{{ memo.created_at }}</td>
        <td align="center">
          <a id="edit_btn" href="{% url 'memo:edit_memo' pk=memo.id %}">Edit</a>
        </td>
        <td align="center">
          <a id="delete_btn" href="{% url 'memo:delete_memo' pk=memo.id %}">Remove</a>
        </td>
      </tr>
      {% endfor %}
    </tbody>
  </table>
  {% endif %}
  <br />
  <a id="new_memo_link" href="{% url 'memo:create_memo' %}"> Create New Memo</a
  ><br />
  <a id="home_link" href="{% url 'home' %}">Back to Home</a>
</div>
{% endblock content %}
memo_form.html
{# Project: MemoPad #} {# Memo nput form #} {% extends "base.html" %} {% block title %}Editing Memo - Hello World!{% endblock %} {% block content %}
<br />
<div class="container">
  <h4>Edit memo</h4>
  {% if form.errors and form.errors is not None and id != '0' %} {% for field in form %} {% for error in field.errors %}
  <div class="alert alert-error">
    <strong>・{{ field.label|escape }}: {{ error| escape }}</strong>
  </div>
  {% endfor %} {% endfor %} {% for error in form.non_field_errors %}
  <div class="alert alert-error">
    <strong>・{{ error|escape }}</strong>
  </div>
  {% endfor %} {% endif %}
  <form action="" method="post">
    {% csrf_token %}
    <label>{{ form.content.label }}</label>
    {{ form.content }} <br />
    <input type="submit" value="Save" id="submit_btn" />
  </form>
  <br />
  <a id="list_link" href="{% url 'memo:list_memo' %}">Back toList</a>
</div>
{% endblock %}

5.5.4 設定の変更(settings.py)

作成した templates フォルダを Django に認識させる必要があります。

  • MemoPad/settings.py の TEMPLATES 内にある 'DIRS' を以下のように修正します。
'DIRS': [os.path.join(BASE_DIR, 'templates')],

※ import os がファイル先頭にない場合は、追加してください。

5.6 ルーティングの設定

5.6.1 プロジェクト全体のURL設定(Project URLs)

プロジェクト全体の「案内板」に、ホームページの表示と memo アプリへの誘導を追加します 。

  • 編集ファイル: MemoPad/MemoPad/urls.py
  • 記述内容: 以下のように書き換えてください 。
MemoPad / MemoPad / urls.py
from django.contrib import admin
from django.urls import path, include
from memo.views.views import Home # Homeビューをインポート

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', Home.as_view(), name='home'), # サイトのトップページ
    path('memo/', include('memo.urls')),   # memoアプリへ誘導
]

5.6.2 メモアプリ専用のURL設定(App URLs)

次に、memo アプリ内での詳細な行き先(一覧・作成・編集・削除)を定義します 。

  • 編集ファイル: memo/urls.py
  • 記述内容: 作成済みの4つのViewを登録します 。
memo / urls.py
from django.urls import path
from memo.views import views
from memo.views.memo.views import MemoListView, MemoCreateView, MemoUpdateView, MemoDeleteView

app_name = 'memo'
urlpatterns = [
    # 各機能(CRUD)に対応するURLパス [cite: 1784-1787]
    path('memos', MemoListView.as_view(), name='list_memo'),
    path('memos_edit/<int:pk>', MemoUpdateView.as_view(), name='edit_memo'),
    path('memos_new', MemoCreateView.as_view(), name='create_memo'),
    path('memos_delete/<int:pk>', MemoDeleteView.as_view(), name='delete_memo'),
]

5.6.3 動作確認(テストラン)

すべてのファイルを保存したら、サーバーを起動して動作を確認しましょう 。

  1. ターミナルで実行
    bash
    python manage.py runserver
    
  2. ブラウザで以下にアクセス
    http://127.0.0.1:8000/ →「Welcome to my site」と表示されますか?
    http://127.0.0.1:8000/memo/memos : メモの一覧画面が表示されますか?
    これで、CRUD(作成・読み出し・更新・削除)のすべての機能が繋がりました。
    実際に「Create New Memo」から新しいメモを保存して、一覧に反映されるか試してみてください。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?