概要
Django4がリリースされたこともあり、検証も兼ねて超初歩的なブログアプリを作成し、CRUD機能の実装からHerokuへのデプロイまでを一通り行ってみた。
説明内容に誤りがありましたら、ご教授いただけますと幸いです。
開発環境
- Python=3.9.7
- Django=4.0
- PostgreSQL=13.5
- psycopg2=2.8.6
*Heroku用に追加
- django-heroku=0.3.1
- gunicorn=20.1.0
アプリケーションの作成からindex.htmlを表示させるまで
プロジェクトの作成
$ django-admin startproject django_project
$ cd django_project
$ python manage.py startapp blog_app
作成したアプリの有効化
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog_app', # 作成したアプリ名を追加
]
アプリケーションで個別に設定したルーティングを大元のルーティングに適用させる(ここでは、blog_app
のルーティングを適用させている)
[django_project/urls.py]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog_app/', include('blog_app.urls')),
]
index.html
の作成
index.html
の作成
blog_app
配下にtemplates/blog_app
フォルダを作成し、その中にindex.html
を作成する
[blog_app/templates/blog_app/index.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Index Page</h1>
</body>
</html>
コントローラの設定
[blog_app/views.py]
from django.shortcuts import render
def index(request):
return render(request, 'blog_app/index.html')
ルーティングの設定
[blog_app/urls.py]
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
サーバを起動し、http://localhost:8000/blog_app/
にアクセスしてindex.html
が表示されれば成功。
PostgreSQLのインストール
*ローカルにPostgreSQLがインストールされている前提です。
DjangoでPostgreSQLを使用するために、psycopg2と言うパッケージが必要です。
psycopg2のインストールします。(Macの場合、openssl必要/環境によってpsycopg2のインストール方法が異なるようなので、適宜変更してください。)
$ brew install openssl
$ echo 'export PATH="/opt/homebrew/opt/openssl@3/bin:$PATH"' >> ~/.zshrc
$ source ~/.zshrc
$ pip install psycopg2==2.8.6
$ export LDFLAGS="-L/opt/homebrew/opt/curl/lib -L/opt/homebrew/opt/openssl/lib"
$ export CPPFLAGS="-I/opt/homebrew/opt/curl/include -I/user/local/opt/openssl/include"
ロールとデータベースの作成
$ psql postgres
postgres=# CREATE DATABASE django_project;
postgres=# CREATE USER USERNAME WITH PASSWORD 'password';
DjangoでPostgreSQLを使用する設定
[django_project/settings.py]
# 省略
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'django_project',
'USER': 'ロール名',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '5432',
}
}
#省略
サーバを起動し、ブラウザ上でアプリケーションを表示できれば成功
モデルの作成
テーブル定義
[blog_app/models.py]
from django.db import models
class Blog(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(max_length=300)
マイグレーションファイルの作成
$ python manage.py makemigrations blog_app
マイグレーションの実行
$ python manage.py migrate
コントローラの設定
[blog_app/views.py]
from django.shortcuts import render
from django.http import HttpResponse
from .models import Blog
def index(request):
data = Blog.objects.all()
params = {
'data': data,
}
return render(request, 'blog_app/index.html', params)
index.html
を作成
[blog_app/templates/blog_app/index.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>index</h1>
<table>
<tr>
<th>ID</th>
<th>TITLE</th>
<th>CONTENT</th>
</tr>
{% for item in data %}
<tr>
<td>{{item.id}}</td>
<td>{{item.title}}</td>
<td>{{item.content}}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
サーバを起動し、ブラウザ上でアプリケーションを表示できれば成功
Create機能の追加
forms.py
を作成し、フォームの内容を記述
[blog_app/forms.py]
from django import forms
class BlogForm(forms.Form):
title = forms.CharField(label='TITLE', max_length=100)
content = forms.CharField(label='CONTENT', max_length=300)
create.html
を作成
[blog_app/templates/blog_app/create.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Create</h1>
<form action="{% url 'create' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="click">
</form>
</body>
</html>
コントローラにcreate
関数を作成
[blog_app/views.py]
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import redirect
from .models import Blog
from .forms import BlogForm
def index(request):
data = Blog.objects.all()
params = {
'data': data,
}
return render(request, 'blog_app/index.html', params)
def create(request):
params = {
'form': BlogForm(),
}
if (request.method == 'POST'):
title = request.POST['title']
content = request.POST['content']
blog = Blog(title=title, content=content)
blog.save()
return redirect(to='/blog_app')
return render(request, 'blog_app/create.html', params)
ルーティングを修正
[blog_app/urls.py]
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('create', views.create, name='create'),
]
サーバを起動し、ブラウザ上でアプリケーションを表示できれば成功
ModelFormの利用
[blog_app/forms.py]
from django import forms
from .models import Blog
class BlogForm(forms.ModelForm):
class Meta:
model = Blog
fields = ['title', 'content']
[blog_app/views.py]
# 省略
def create(request):
if (request.method == 'POST'):
obj = Blog()
blog = BlogForm(request.POST, instance=obj)
blog.save()
return redirect(to='/blog_app')
params = {
'form': BlogForm(),
}
return render(request, 'blog_app/create.html', params)
サーバを起動し、ブラウザ上でアプリケーションを表示できれば成功
Update機能の追加
ルーティングの追加
[blog_app/urls.py]
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('create', views.create, name='create'),
path('edit/<int:num>', views.edit, name='edit'),
]
indexページに編集リンクを追加
[blog_app/templates/blog_app/index.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Index</h1>
<table>
<tr>
<th>ID</th>
<th>TITLE</th>
<th>CONTENT</th>
</tr>
{% for item in data %}
<tr>
<td>{{item.id}}</td>
<td>{{item.title}}</td>
<td>{{item.content}}</td>
<td><a href="{% url 'edit' item.id %}">Edit</a></td>
</tr>
{% endfor %}
</table>
</body>
</html>
blog_app/templates/blog_app
に新たにedit.html
を作成し、以下のコードを記述
[blog_app/templates/blog_app/edit.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Edit</h1>
<form action="{% url 'edit' id %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="click">
</form>
</body>
</html>
edit関数の作成
[blog_app/views.py]
# 省略
def edit(request, num):
obj = Blog.objects.get(id=num)
if (request.method == 'POST'):
blog = BlogForm(request.POST, instance=obj)
blog.save()
return redirect(to='/blog_app')
params = {
'id': num,
'form': BlogForm(instance=obj),
}
return render(request, 'blog_app/edit.html', params)
サーバを起動し、ブラウザ上でアプリケーションを表示できれば成功
Delete機能の追加
ルーティングの追加
[blog_app/urls.py]
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('create', views.create, name='create'),
path('edit/<int:num>', views.edit, name='edit'),
path('delete/<int:num>', views.delete, name='delete'),
]
indexページに削除リンクを追加
[blog_app/templates/blog_app/index.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Index</h1>
<table>
<tr>
<th>ID</th>
<th>TITLE</th>
<th>CONTENT</th>
</tr>
{% for item in data %}
<tr>
<td>{{item.id}}</td>
<td>{{item.title}}</td>
<td>{{item.content}}</td>
<td><a href="{% url 'edit' item.id %}">Edit</a></td>
<td><a href="{% url 'delete' item.id %}">Delete</a></td>
</tr>
{% endfor %}
</table>
</body>
</html>
blog_app/templates/blog_app
に新たにdelete.html
を作成し、以下のコードを記述
[blog_app/templates/blog_app/delete.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Delete</h1>
<table>
<tr>
<th>ID</th>
<td>{{obj.id}}</td>
</tr>
<tr>
<th>TITLE</th>
<td>{{obj.title}}</td>
</tr>
<tr>
<th>CONTENT</th>
<td>{{obj.content}}</td>
</tr>
<form action="{% url 'delete' id %}" method="post">
{% csrf_token %}
<tr>
<th>
<td><input type="submit" value="click"></td>
</th>
</tr>
</form>
</table>
</body>
</html>
delete関数の作成
[blog_app/views.py]
# 省略
def delete(request, num):
blog = Blog.objects.get(id=num)
if (request.method == 'POST'):
blog.delete()
return redirect(to='/blog_app')
params = {
'id': num,
'obj': blog,
}
return render(request, 'blog_app/delete.html', params)
Read機能の追加
ルーティングの追加
[blog_app/urls.py]
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('create', views.create, name='create'),
path('edit/<int:num>', views.edit, name='edit'),
path('delete/<int:num>', views.delete, name='delete'),
path('detail/<int:num>', views.detail, name='detail'),
]
indexページに詳細リンクを追加
[blog_app/templates/blog_app/index.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Index</h1>
<table>
<tr>
<th>ID</th>
<th>TITLE</th>
<th>CONTENT</th>
</tr>
{% for item in data %}
<tr>
<td>{{item.id}}</td>
<td>{{item.title}}</td>
<td>{{item.content}}</td>
<td><a href="{% url 'detail' item.id %}">Detail</a></td>
<td><a href="{% url 'edit' item.id %}">Edit</a></td>
<td><a href="{% url 'delete' item.id %}">Delete</a></td>
</tr>
{% endfor %}
</table>
</body>
</html>
blog_app/templates/blog_app
に新たにdetail.html
を作成し、以下のコードを記述
[blog_app/templates/blog_app/detail.html]
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>blog_app</title>
</head>
<body>
<h1>Detail</h1>
<table>
<tr>
<th>ID</th>
<td>{{obj.id}}</td>
</tr>
<tr>
<th>TITLE</th>
<td>{{obj.title}}</td>
</tr>
<tr>
<th>CONTENT</th>
<td>{{obj.content}}</td>
</tr>
</table>
</body>
</html>
detail関数の作成
[blog_app/views.py]
# 省略
def detail(request, num):
blog = Blog.objects.get(id=num)
params = {
'id': num,
'obj': blog,
}
return render(request, 'blog_app/detail.html', params)
Herokuへのデプロイ
公式:https://devcenter.heroku.com/ja/articles/django-app-configuration
設定
django-herokuとgunicornをインストール
$ pip install django_heroku gunicorn
Procfile
とruntime.txt
とrequirements.txt
の3つのファイルを作成する
1. Procfile
の作成
web: gunicorn django_project.wsgi
2. runtime.txt
の作成
python-3.9.7
3. プロジェクトディレクトリで以下のコマンドを実行し、requirements.txt
を作成
$ pip freeze > requirements.txt
[django_project/settings.py]
from pathlib import Path
import django_heroku # 追記
# 省略
# Activate Django-Heroku.
django_heroku.settings(locals()) # 最終行に追記
コミット&デプロイ
$ git add .
$ git commit "add heroku setting"
$ heroku create
$ heroku config:set DISABLE_COLLECTSTATIC=1
$ git push heroku master
$ heroku run python manage.py migrate
$ heroku open
heroku open
コマンドで起動する画面でのページは存在しないため、「Not Found The requested resource was not found on this server.」が表示される。
https://xxxxx-xxxxx-xxxxx.herokuapp.com
に/blog_app
パスを追加してアクセスすれば、アプリが表示されるはずです。