開発環境
この記事の開発環境は下記になります。
macOS sonoma $ python --version Python 3.11.4 $ sqlite3 -version 3.39.5
Djangoのインストール
Djangoのインストールがまだならインストールしましょう。
$ python -m pip install Django
この記事で使用するバージョンは下記です。
$ python -m django --version 5.0.4
プロジェクト作成
適当なディレクトリに移動したら下記コマンドでプロジェクトファイルを作成します。
$ django-admin startproject django_simple_cms
django_simple_cmsというディレクトリが作られるので移動します。
$ cd django_simple_cms
作成されたdjango_simple_cmsの中は次のようなファイル構成となります。
django_simple_cms/ ├ manage.py └ django_simple_cms/ ├ __init__.py ├ settings.py ├ urls.py ├ asgi.py └ wsgi.py
Djangoの開発用サーバーを使用して動作確認をしてみましょう。
$ python manage.py runserver
コマンドを実行すると次のメッセージが表示されます。
Django version 5.0.4, using settings 'django_simple_cms.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
ブラウザでhttp://localhost:8000
にアクセスしてみましょう。
画面に「The install worked successfully! Congratulations!」というメッセージが表示されたら正常に動作しています。
初期設定
日本語環境で使えるように初期設定を行います。
settings.py
の下記項目を編集してください。
django_simple_cms/settings.py
LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo'
データベースの設定は同じファイルのDATABASES
という項目で設定しますが、今回はデフォルト設定のSQLiteを使用しますのでそのまま使用します。
django_simple_cms/settings.py
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': BASE_DIR / 'db.sqlite3', } }
日本語にしたのでブラウザで確認すると今度は「インストールは成功しました!おめでとうございます!」というメッセージに変わっています。
ライブラリのインストール
開発するのに便利なライブラリをインストールします。
Django Debug Toolbar
このライブラリはSQLとかリクエストの値を画面に表示してくれます。
pipでインストールしましょう。
pip install django-debug-toolbar
設定ファイルに下記を追記します。
django_simple_cms/settings.py
INSTALLED_APPS = [ # ... 'debug_toolbar', ] MIDDLEWARE = [ # ... 'debug_toolbar.middleware.DebugToolbarMiddleware', ] # 追加 DEBUG_TOOLBAR_CONFIG = { 'SHOW_TOOLBAR_CALLBACK' : lambda request: True, }
ルーティングにも追記します。
django_simple_cms/urls.py
urlpatterns = [ # ... path('__debug__/', include('debug_toolbar.urls')), ]
Django Debug Toolbarは後ほど解説するテンプレートを作成した時点で確認できるようになります。
postsアプリケーションの作成
Djangoは一つのプロジェクトの中に複数のアプリケーションを作成します。
はじめにお知らせを管理するpostsアプリケーションを作成しましょう。
次のコマンドを実行してください。
$ python manage.py startapp posts
django_simple_cmsディレクトリ以下に下記のファイルが生成されます。
posts/ ├ __init__.py ├ admin.py ├ apps.py ├ migrations/ └ __init__.py ├ models.py ├ tests.py └ views.py
ビューの編集
DjangoはMVCではなくMTV(Model・Template・View)というアーキテクチャになります。
一般的なMVCのControllerにあたる部分がViewと思っていいのではないかと思います。
単純にテキストを表示する処理を作成してみましょう。
posts/views.py
を下記のように編集してみてください。
posts/views.py
from django.http import HttpResponse def index(request): return HttpResponse('お知らせページ')
ルートの編集
作成したビューを表示するようにpostsのルートを編集します。
posts/urls.py
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='index'), ]
編集したルートファイルを読み込めるように、プロジェクトのルートファイルを編集します。
/posts
でアクセスした時postsアプリケーションのルートを読み込むように設定をします。
django_simple_cms/urls.py
from django.contrib import admin from django.urls import include, path urlpatterns = [ path('posts/', include('posts.urls')), path('admin/', admin.site.urls), ]
ブラウザでhttp://localhost:8000/posts
にアクセスしてみましょう。
ビューで設定した「お知らせページ」という文字が表示されます。
マイグレーションの作成
データベースにテーブルを作成します。
Djangoはモデルに設定するとマイグレーションファイルを作成する機能があるのでモデルから作成していきましょう。
posts/models.py
を下記のように修正します。
posts/models.py
from django.db import models class Post(models.Model): title = models.CharField(max_length=255) body = models.TextField() is_public = models.BooleanField(default=True) published_at = models.DateTimeField()
できたら下記コマンドを実行することでマイグレーションファイルが作成されます。
$ python manage.py makemigrations posts
posts/migrations/0001_initial.py
というファイルが作られたことを確認してください。
マイグレーションファイルはPythonファイルですが、次のコマンドでどのようなSQLが実行されるのか確認することができます。
$ python manage.py sqlmigrate posts 0001
出力されたSQLをフォーマットすると下記のようになります。
BEGIN; -- -- Create model Post -- CREATE TABLE "posts_post" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(255) NOT NULL, "body" text NOT NULL, "is_public" bool NOT NULL, "published_at" datetime NOT NULL ); COMMIT;
問題なさそうなのでmigrateコマンドを実行しましょう。
$ python manage.py migrate
これでDBに必要なテーブルが作成されます。確認してみましょう。
データベースの確認
sqlite3コマンドでDBに接続してもいいですが、dbshell
コマンドでDBに接続することもできます。
$ python manage.py dbshell
テーブル一覧の確認
sqlite> .table
posts_postテーブルのスキーマ確認
sqlite> .schema posts_post
マイグレーションファイルを確認したときと同じカラム情報が表示されるはずです。
sqliteを終了します。
sqlite> .quit
管理ユーザーの作成
今回はDjangoのデフォルト管理画面を使用してデータを登録します。
管理画面にログインする為のユーザの作成を行いましょう。
下記コマンドを実行してください。
$ python manage.py createsuperuser
ユーザー名、メールアドレス、パスワードをそれぞれ入力します。
$ ユーザー名: admin $ メールアドレス: admin@example.com $ Password: ********** $ Password (again): *********
下記が表示されれば登録完了です。
Superuser created successfully.
http://localhost:8000/admin
にアクセスするとログイン画面が表示されるので、登録した情報を入力します。
ログインに成功すると管理画面に遷移して下記画像のように表示されます。
管理画面のカスタマイズ
初期状態では「認証と認可」の項目のみ表示されています。
先ほど作成したPostsも管理画面で編集できるように表示してみましょう。
posts/admin.py
を下記のように編集します。
posts/admin.py
from django.contrib import admin from .models import Post admin.site.register(Post)
これでPostsという項目が追加されますが英語なので日本語表記します。
posts/apps.py
のverbose_name
に表示したい名称を設定します。
posts/apps.py
from django.apps import AppConfig class PostsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'posts' verbose_name = '投稿'
posts/models.py
のverbose_name
にも同じように設定します。
posts/models.py
from django.db import models class Post(models.Model): title = models.CharField(max_length=255, verbose_name='タイトル') body = models.TextField(verbose_name='内容') is_public = models.BooleanField(default=True, verbose_name='公開') published_at = models.DateTimeField(verbose_name='公開日') class Meta: verbose_name = '投稿' verbose_name_plural = '投稿'
再度管理画面を確認すると「投稿」という項目が増えて入力項目も日本語になっています。
一覧画面カスタマイズ
一覧ページの項目が「Post object (1)」のような表記になりわかりずらいのでタイトルと公開日を表示するようにします。
ついでにタイトルと内容で検索できるようにもしてみましょう。
posts/admin.py
を下記のように編集します。
posts/admin.py
from django.contrib import admin from .models import Post class PostAdmin(admin.ModelAdmin): list_display = ['title', 'published_at'] search_fields = ['title', 'body'] admin.site.register(Post, PostAdmin)
list_display
が一覧に表示する項目で、search_fields
が検索に使用する項目です。
ブラウザで確認すると下記のように表示されます。
「投稿を追加」ボタンをクリックしていくつか登録してみましょう。
フロント一覧画面の作成
管理画面からデータの登録ができたので、フロント画面を作成して表示してみましょう。
posts/views.py
のIndexView
を下記のように修正します。
データの一覧ページはgeneric.ListView
クラスを継承することで簡単に作ることができます。
posts/views.py
from django.http import HttpResponse from django.views import generic from .models import Post class IndexView(generic.ListView): model = Post
このビューにアクセスできるようにルーティングも編集します。
posts/urls.py
urlpatterns = [ path('', views.IndexView.as_view(), name='index'), ]
次にテンプレートを作成します。
head要素など全ページ共通で使用する部分を書くレイアウトファイルになります。
posts/templates/base.html
<!DOCTYPE html> <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.0"> <title>株式会社Sample</title> </head> <body> {% block main %} {% endblock %} </body> </html>
block main
の部分に各ページのテンプレート内容を表示するように指定します。
一覧表示部分を作成していきましょう。
generic.ListView
を継承したクラスでは自動的に「モデル名_list.html」ファイルが読み込まれます。
なので今回はpost_list.html
というファイル名で作成します。
またモデルから取得したデータはpost_list
という変数に入っているので展開しましょう。
posts/templates/posts/post_list.html
{% extends "base.html" %} {% block main %} <h1>お知らせ</h1> {% if post_list %} <ul> {% for post in post_list %} <li>{{ post.title }}</li> {% endfor %} </ul> {% else %} <p>お知らせはありません。</p> {% endif %} {% endblock %}
ブラウザで確認すると管理画面で入力した内容が表示されます。
ただ今の状態だと昇順で全件表示されてしまいますね。
下記条件で表示させてみましょう。
- 公開日(published_at)で降順
- 10件
- 公開(is_public)が表示(True)のもの
ビューファイルのget_queryset
メソッドに検索条件を記述することで反映されます。
posts/views.py
class IndexView(generic.ListView): def get_queryset(self): return ( Post.objects .filter(is_public=True) .order_by('-published_at')[:10] )
再度ブラウザで確認すると条件通りに表示されたと思います。
ページネーション(ページ分割)
一覧を10件指定して表示しましたが、過去の投稿も見れるようにしたいですね。
1ページに表示する数は抑えつつ10件以上表示する方法としてはページネーション機能を使用してページ分割するのが一般的です。
views.py
を下記のように編集します。
paginate_by
で一ページに表示する数を指定して、get_queryset
で指定していた件数指定は削除しましょう。
posts/views.py
class IndexView(generic.ListView): paginate_by = 10 def get_queryset(self): return ( Post.objects .filter(is_public=True) .order_by('-published_at') )
post_list.html
にページナビゲーションを表示するように追記します。
posts/templates/posts/post_list.html
{% if is_paginated %} {% if page_obj.has_previous %} <a href="?page=1"> « </a> <a href="?page={{ page_obj.previous_page_number }}"> ‹ </a> {% endif %} {% for number in page_obj.paginator.page_range %} {% if page_obj.number == number %} {{ number }} {% else %} <a href="?page={{ number }}">{{ number }}</a> {% endif %} {% endfor %} {% if page_obj.has_next %} <a href="?page={{ page_obj.next_page_number }}"> › </a> <a href="?page={{ page_obj.paginator.num_pages }}"> » </a> {% endif %} {% endif %}
静的ファイルの表示
CSSファイルを例に静的ファイルを表示してみます。
最初に使用するCSSファイルを適当に作り配置します。
static/css/style.css
h1 { color: red; }
settings.py
にSTATICFILES_DIRS
という項目を追記して静的ファイルを配置するディレクトリを指定します。
今回はstatic
ですね。
django_simple_cms/settings.py
STATICFILES_DIRS = [ BASE_DIR / 'static', ]
レイアウトHTMLでload static
を追記して配置したCSSを読み込みましょう。
posts/templates/base.html
{% load static %} <!DOCTYPE html> <html lang="ja"> <head> ... <link rel="stylesheet" href="{% static 'css/style.css' %}">
ブラウザで表示してh1が赤色になっていることを確認してください。
詳細ページの作成
次に一覧からリンクする詳細ページを作成しましょう。
ビューにgeneric.DetailView
を継承したDetailView
クラスを作成します。
posts/views.py
# ... class DetailView(generic.DetailView): model = Post
詳細ページのテンプレートはデフォルトでpost_detail.html
が読み込まれます。
対応したデータも自動的に取得されpost
変数に代入されますので、この変数を展開しましょう。
posts/templates/posts/post_detail.html
{% extends 'base.html' %} {% block main %} <h1>{{ post.title }}</h1> <p>公開日:{{ post.published_at|date:'Y年m月d日' }}</p> <div>{{ post.body }}</div> {% endblock %}
詳細ページにアクセスできるようにルーティングの設定を行います。
posts/urls.py
app_name = 'posts' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), ]
int:pk
指定しているのでプライマリキー(id)でアクセスした際詳細ページが表示されるようになります。
app_name
を指定しておくとのちにアプリケーションを追加した時に区別がしやすくなります。
ブラウザでhttp://localhost:8000/posts/1
にアクセスして詳細ページが表示されるか確認してみましょう。
非公開投稿にアクセスできないようにする
詳細ページを表示することができましたが、今の状態だとすべての投稿が表示されてしまいますね。
非公開にした投稿ページにアクセスしたときは404ページになるようにしましょう。
一覧と同じようにviews.py
のDetailView
に検索条件を追加します。
posts/views.py
# ... class DetailView(generic.DetailView): def get_queryset(self): return Post.objects.filter(is_public=True)
これで、非公開(is_public=False)にしたページにアクセスすると404ページが表示されるようになります。
一覧からリンク設定
先ほど作成した一覧ページからリンクを設定して遷移できるようにしてみましょう。
post_list.html
のリスト部分を下記のように編集します。
posts/templates/posts/post_list.html
<li><a href="{% url 'posts:detail' post.id %}">{{ post.title }}</a></li>
posts:detail
の部分はurls.py
で設定したapp_name
とname
を:で繋いだ文字列です。
これで一覧から詳細ページへリンクすることができました。
すごく簡単にでしたが、データベースの作成から管理画面からの登録、フロントの表示まで行うことができました。
Djangoはもう少しやっていこうと思いますのでまた!!
ソースコードはGitHubにのせてます。
下記サイトを参考にさせて頂きました。