ブログアプリの作成
定番だと思いますが、ブログを作ってみましょう。
django-lesson配下にterminalで移動していることを確認後、以下のコマンドを実行してください。
1 2 3 4 |
pwd /Users/<user>/Desktop/django-lesson make app app=blog |
このコマンドは、Makefileに記述されたDjangoのアプリケーションを作成するためのコマンドです。
これで、アプリケーションを作成するために必要なフォルダが作成されます。
1 2 3 |
ls app/ app blog db.sqlite3 manage.py |
app フォルダ配下にあるsettings.pyファイルに作成したアプリケーションを認識させる設定を加えましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
vi app/app/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # myapp 'blog', # new ] |
DBの導入
Djangoは、デフォルトで、sqliteというデータベースを使います。
しかし、現場では、MySQLやPostgreSQLの方がよく使われるので、ここではPostgreSQLを使用することにします。
「Djangoアプリケーション開発 ~事前準備編~」では、PostgreSQLのコンテナを作成しているので、DjangoとPostgreSQLを連携する設定を行います。
appフォルダ内にあるsettings.pyの「DATABASES」の設定ファイルを以下のように書き換えてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
vi app/app/settings.py # DATABASES = { # 'default': { # 'ENGINE': 'django.db.backends.sqlite3', # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # } #} DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'HOST': os.environ.get('DB_HOST'), 'NAME': os.environ.get('DB_NAME'), 'USER': os.environ.get('DB_USER'), 'PASSWORD': os.environ.get('DB_PASS'), } } |
os.environ.getは、docker-compose.ymlに設定した環境変数の値を取得します。
コンテナを立ち上げていた場合は、Ctrl + c でコンテナを停止した後、以下のコマンドを打ち込んでください。
1 2 3 4 5 |
# ビルドを行う docker-compose build # コンテナを立ち上げる(バックグラウンドで立ち上げる) docker-compose up -d |
localhost:8000にアクセスして、Djangoのスタート画面が表示されたら成功です。

補足)
コンテナ立ち上げ時に「dオプション」を指定しました。
このオプションは、コンテナをバックグランドで起動します。
停止したい場合は、以下のコマンドを実行してください。
1 |
docker-compose down |
ログを見たいときは、以下のコマンドを実行してください。
1 |
docker-compose logs |
投稿モデルの作成
投稿モデルを作成してみましょう。
Djangoでは、モデルの作成をアプリケーション配下のmodels.pyに記述します。
このファイルは、アプリケーション作成時に一緒作成されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
vi app/blog/models.py from django.db import models from django.utils import timezone from django.contrib.auth.models import User class PublishedManager(models.Manager): def get_queryset(self): return super(PublishedManager, self).get_queryset().filter(status='published') class Post(models.Model): STATUS_CHOICES = ( ('draft', 'Draft'), ('published', 'Published'), ) title = models.CharField(max_length=250) slug = models.SlugField(max_length=250, unique_for_date='publish') author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts') body = models.TextField() publish = models.DateTimeField(default=timezone.now) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft') objects = models.Manager() # The default manager published = PublishedManager() # Our custom manager class Meta: ordering = ('-publish',) def __str__(self): return self.title |
Djangoでは、このモデルに記載した内容からデータベースを作成します。
データベースを作成するためには、マイグレーションを行う必要があります。
以下のコマンドを実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
make migrate Starting django-lesson_db_1 ... done Migrations for 'blog': blog/migrations/0001_initial.py - Create model Post docker-compose run --rm app sh -c "python manage.py migrate" Starting django-lesson_db_1 ... done Operations to perform: Apply all migrations: admin, auth, blog, contenttypes, sessions Running migrations: Applying blog.0001_initial... OK |
データベースの作成に成功したか確認するために、blogアプリケーション配下のadmin.pyに以下の記述を行いましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
vi app/blog/admin.py from django.contrib import admin from .models import Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ('title', 'slug', 'author', 'publish', 'status') list_filter = ('status', 'created', 'publish', 'author') search_fields = ('title', 'body') prepopulated_fields = {'slug': ('title',)} raw_id_fields = ('author',) date_hierarchy = 'publish' ordering = ('status', 'publish') |
Djangoの便利機能の一つに、管理画面があります。
ブラウザ上で、「localhost:8000/admin」と打ち込むと管理画面に遷移することができます。
ただし、管理者権限を持つユーザーを作成しないとログインできません。
以下のコマンドで作成しましょう。
1 2 3 4 5 6 7 |
make admin Username (leave blank to use 'user'): admin Email address: admin@example.co.jp Password: # 適当なパスワード Password (again): # 適当なパスワード Superuser created successfully. |
作成した管理ユーザーにて、ログインしてみましょう。
Postモデルはありましたでしょうか?

「Posts」になっていると思いますが、Djangoの仕様なので気にしないでください。
「+Add」を押下して、適当にデータを追加してみましょう。
データが登録されたら、問題なく動作しています。

Viewの作成
Djangoでは、views.pyにクライアントからのリクエストを裁く処理を記載します。
投稿一覧と投稿詳細を作成してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
vi app/blog/views.py from django.shortcuts import render, get_object_or_404 from .models import Post def post_list(request): # Show all post with publish status posts = Post.published.all() return render(request, 'blog/post/list.html', {'posts': posts}) def post_detail(request, year, month, day, post): """Show post datail""" post = get_object_or_404(Post, slug=post, status='published', publish__year=year, publish__month=month, publish__day=day) return render(request, 'blog/post/detail.html', {'post': post}) |
URLの作成
続いては、URL を作成しましょう。
例えば、ブラウザ上で、「localhost:8000」と打ち込んだ時に、サーバー側で実行した処理を指定するときに使用します。
実際、コードを見てもらった方がはやいでしょう。
Djangoでは、urls.py 内にその記述を行いますが、blogアプリケーションを作成時には、一緒に作成されないので、新たに作成します。
1 |
touch app/blog/urls.py |
では、処理内容を記述します。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
vi app/blog/urls.py from django.urls import path from . import views app_name = 'blog' urlpatterns = [ path('', views.post_list, name='post_list'), path('<int:year>/<int:month>/<int:day>/<slug:post>/', views.post_detail, name='post_detail'), ] |
実は、appプロジェクト内にもurls.pyが存在しているので、そちらにも変更を加えます。
1 2 3 4 5 6 7 8 9 10 |
vi app/app/urls.py from django.contrib import admin from django.urls import path, include # new urlpatterns = [ path('admin/', admin.site.urls), path('blog/', include('blog.urls', namespace='blog')), # new ] |
Canonical URL の設定
ブログらしく、Canonical URL の設定も加えておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
vi app/blog/models.py from django.db import models from django.utils import timezone from django.contrib.auth.models import User from django.urls import reverse # new class PublishedManager(models.Manager): def get_queryset(self): return super(PublishedManager, self).get_queryset().filter(status='published') class Post(models.Model): STATUS_CHOICES = ( ('draft', 'Draft'), ('published', 'Published'), ) title = models.CharField(max_length=250) slug = models.SlugField(max_length=250, unique_for_date='publish') author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts') body = models.TextField() publish = models.DateTimeField(default=timezone.now) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft') objects = models.Manager() # The default manager published = PublishedManager() # Our custom manager class Meta: ordering = ('-publish',) def __str__(self): return self.title # new def get_absolute_url(self): """Get absolue url with reverse method""" return reverse('blog:post_detail', args=[self.publish.year, self.publish.month, self.publish.day, self.slug]) |
一応、マイグレーションをしておきましょう。マイグレーションは、データベースの構造(カラムやプロパティ)を変更した時に、データベースに変更内容を適用します。
1 |
make migrate |
templateファイル
views.pyで処理したデータをtemplateファイルに渡し、それを画面上に表示させます。
1 2 3 4 5 6 |
mkdir app/blog/templates mkdir mkdir app/blog/templates/blog mkdir app/blog/templates/blog/post touch app/blog/templates/blog/base.html touch app/blog/templates/blog/post/list.html touch app/blog/templates/blog/post/detail.html |
それぞれのファイルに以下を記述しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
vi app/blog/templates/blog/base.html {% load static %} <!DOCTYPE html> <html> <head> <title>{% block title%}{% endblock %}</title> <link href="{% static 'css/blog.css' %}" rel="stylesheet"> </head> <body> <div id="content"> {% block content %} {% endblock %} </div> <div id="sidebar"> <h2>My blog</h2> <p>This is my blog.</p> </div> </body> </html> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
vi app/blog/templates/blog/post/list.html {% extends "blog/base.html" %} {% block title %}My Blog{% endblock %} {% block content %} <h1>My Blog</h1> {% for post in posts %} <h2> <a href="{{ post.get_absolute_url }}"> {{ post.title }} </a> </h2> <p class="date"> Published {{ post.publish }} by {{ post.author }} </p> {{ post.body|truncatewords:30|linebreaks }} {% endfor %} {% endblock %} |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
vi app/blog/templates/blog/post/detail.html {% extends "blog/base.html" %} {% block title%}{{ post.title }}{% endblock %} {% block content %} <h1>{{ post.title }}</h1> <p class="date"> Published {{ post.publish }} by {{ post.author }} </p> {{ post.body|linebreaks }} {% endblock %} |
動作確認
ここまで設定できたら、動作確認してみましょう。
1 2 |
docker-compose down docker-compose up -d |
「localhost:8000/blog」にアクセスしてみましょう。

上記の画面が表示されましたでしょうか。
詳細画面も表示してみましょう。(例「http://localhost:8000/blog/2019/8/17/first-post/」)

もしかしたら docker-compose down の影響で以下の事象が発生するかもしれません。
・データが削除された
・localhost:8000/blogにアクセスしてもエラー画面が表示される
「docker-compose down」は、既存のコンテナを完全に削除します。Dockerの設定が不十分の場合はデータが消えたり、データベースとアプリケーションの連携がうまく行かなくなる可能性があります。docker-compose logs コマンドでエラー内容を確認してみてください。
おわりに
次は、投稿ページを作成してみましょう。^^
コメントを残す
コメントを投稿するにはログインしてください。