はじめに
続き物の記事になります。前回の記事を読んでいただくとより流れが掴めるかと思われますが、本記事から読み始めて頂いても問題ありません。
環境情報
- MacBook Air (Monterey)
- Docker Compose version v2.6.1
導入
俺は高校生探偵、工○新○。
幼馴染で同級生の毛◯蘭と遊園地へ遊びに行って、黒ずくめの男の怪しげな取引現場を目撃した。
ワイ「なんて感じで面白い人生を送りたかったな〜(ホジホジ」
ワイ「さて、前は Python
+ Django
+ Docker
で環境構築したんやったな 」
ワイ「何作るかな〜」
ワイ「せや、やっぱ最初に作るんは伝家の宝刀 "TODOアプリ"
やな(キリッ」
本編・・・の前に(前回を読んでいない場合は飛ばしてください)
前回の反省(長いので折りたたみ)
ワイ「そういえば、あの後色々調べてたら他のサイトでやってるチュートリアルを見つけたんやが」
ワイ「なんやワイの作ったサンプルと全然見た目ちゃうんよな〜」
djangogirls様から引用↓
ワイ「なんでやろな」
ワイ「ん・・・?」
ワイ「あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛」
ワイ氏が書いたrequirements.txt
Django>=1.8,<2.0
psycopg2
\(^o^)/
ワイ「アホや・・・ちゃんと調べろや自分・・・」
ワイ「しゃあないな、バージョンアップするか」
アップデート作業
ワイ「まずはrequirements.txt
をちょちょいとな」
ワイ「今回はdjangogirls通りにやってみるか」
- Django>=1.8,<2.0
+ Django~=3.2.10
psycopg2
ワイ「直したし作り直しやな」
ワイ「ついでにディレクトリも作り直すか、TODO作るしな」
ワイ「前回作ったディレクトリとかも削除するで」
// 関連ファイルの削除
rm manage.py
// プロジェクトディレクトリの削除
rm -rf composeexample
// コンテナの停止&削除
docker-compose down
// パッケージ類の再インストール・コンテナ作成
docker-compose build
// Djangoプロジェクトの作成
docker-compose run web django-admin.py startproject config .
ワイ「ほんでデータベースの設定やな」
cd config && vi settings.py
// 設定部分を以下に書き換える
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgres',
'USER': 'postgres',
'PASSWORD': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}
TIME_ZONE = 'Asia/Tokyo'
LANGUAGE_CODE = 'ja'
// コンテナの起動
docker-compose up -d
ワイ「今回からはup -d
でバックグラウンドで起動するで」
ワイ「ほな起動したし確認しよか」
ワイ「ええかんじやな!」
本編
ワイ「とりあえずおさらいしよか」
-rw-r--r-- 1 user staff 155B 8 5 12:17 Dockerfile
-rw-r--r-- 1 user staff 349B 8 5 12:33 docker-compose.yml
-rwxr-xr-x 1 user staff 660B 8 10 10:00 manage.py*
-rw-r--r-- 1 user staff 24B 8 10 09:52 requirements.txt
drwxr-xr-x 8 user staff 256B 8 10 10:02 config/
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'postgres',
'USER': 'postgres',
'PASSWORD': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}
TIME_ZONE = 'Asia/Tokyo'
LANGUAGE_CODE = 'ja'
ワイ「こんなもんやな」
ワイ「今回はdjangogirlsとかその辺を見ながらやってくで」
アプリケーションの作成
ワイ「別ディレクトリに分けて開発していくみたいやな」
ワイ「ほなコマンド打ってくで」
docker-compose exec web python manage.py startapp todo
ll total 32
-rw-r--r-- 1 user staff 155B 8 5 12:17 Dockerfile
drwxr-xr-x 8 user staff 256B 8 10 11:07 config/
-rw-r--r-- 1 user staff 349B 8 5 12:33 docker-compose.yml
-rwxr-xr-x 1 user staff 662B 8 10 11:02 manage.py*
-rw-r--r-- 1 user staff 24B 8 10 09:52 requirements.txt
drwxr-xr-x 9 user staff 288B 8 10 11:07 todo/
ワイ「新しくtodo
ディレクトリができたな」
ワイ「なになに・・・作ったアプリを登録せなあかんみたいやな」
ワイ「config/settings.py
を変更するんか」
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo.apps.TodoConfig', // この1行を追記する
]
ワイ「これでええみたいやな」
TODOテーブルの作成
ワイ「どうやらテーブル作る時はモデル
ってのを定義するみたいやな」
ワイ「なんやLaravelみたいやな」
ワイ「まま、ええわ。ほなやってくで」
from django.db import models
# Create your models here.
class Todo(models.Model):
title = models.CharField("名前", max_length=100)
description = models.TextField("タスク内容", blank=True)
def __str__(self):
return self.title
ワイ「こんなかんじでええらしいな」
ワイ「モデルについての詳しい話は公式のドキュメント読んでな」
マイグレーション
ワイ「モデルを定義したらマイグレーションファイルを作るんやな」
docker-compose exec web python makemigration todo
Migrations for 'todo':
todo/migrations/0001_initial.py
- Create model Todo
ワイ「できたみたいやな、簡単や」
ワイ「マイグレーションファイルを作ったってことは・・・」
ワイ「"migrate"やな」
docker-compose exec web python migrate todo
Operations to perform:
Apply all migrations: todo
Running migrations:
Applying todo.0001_initial... OK
スーパーユーザの作成
ワイ「作ったテーブル(モデル)を確認したいな」
ワイ「なになに・・・これか」
ワイ「とりあえずadmin.py
に登録したら見れるらしいな」
from django.contrib import admin
from .models import Todo
# Register your models here.
admin.site.register(Todo)
ワイ「こうやな」
ワイ「admin言うくらいやしスーパーユーザがいるみたいや」
docker-compose exec web python manage.py createsuperuser
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
Traceback (most recent call last):
File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "auth_user" does not exist
LINE 1: ...user"."is_active", "auth_user"."date_joined" FROM "auth_user...
^
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/code/manage.py", line 22, in <module>
main()
File "/code/manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.9/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 79, in execute
return super().execute(*args, **options)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.9/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 100, in handle
default_username = get_default_username(database=database)
File "/usr/local/lib/python3.9/site-packages/django/contrib/auth/management/__init__.py", line 141, in get_default_username
auth_app.User._default_manager.db_manager(database).get(
File "/usr/local/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 431, in get
num = len(clone)
File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 262, in __len__
self._fetch_all()
File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 1324, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/usr/local/lib/python3.9/site-packages/django/db/models/query.py", line 51, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/usr/local/lib/python3.9/site-packages/django/db/models/sql/compiler.py", line 1175, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 98, in execute
return super().execute(sql, params)
File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 66, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.9/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.9/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "auth_user" does not exist
LINE 1: ...user"."is_active", "auth_user"."date_joined" FROM "auth_user...
ワイ「また長いエラー文やな」
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
ワイ「python manage.py migrate
しろって書いてるな」
ワイ「さっきやったのとは別なんかいな」
docker-compose exec web python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions, todo
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 sessions.0001_initial... OK
ワイ「ほ〜ん(完全理解)」
ワイ「もっかいやってみるか」
docker-compose exec web python manage.py createsuperuser
ユーザー名 (leave blank to use 'root'): 好きな名前
メールアドレス: 空でok
Password:
Password (again):
Superuser created successfully.
ワイ「できたんか?」
ワイ「早速adminページにアクセスや」
ワイ「Todosってのを押したらデータを入れれるんか」
ワイ「今回は適当に一つデータ入れてみたで」
template
ワイ「次は見える部分の実装やな」
mkdir -p todo/templates/todo
touch todo/templates/todo/todo_list.html
ワイ「なんかtodo
ディレクトリの中にtodoディレクトリを作るんは違和感あるな」
??「後々楽する為ですよ」
ワイ「ほへぇ〜」
ワイ「とりあえずアレ・・・書くか」
<html>
<head>
<title>todo</title>
</head>
<body>
<h1>hello world</h1>
</body>
</html>
ワイ「やっぱ最初はこれや」
urlのお話
ワイ「djangoのurlはurls.py
ってやつで定義するんやな」
ワイ「これはtodo/
じゃなくてconfig/
の方にあるな」
ワイ「困ったら以下をコピペしてな」
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('todo.urls')),
]
ワイ「これでドメイン直下へのアクセスはblog.urls
にリダイレクトされるんやな」
ワイ「ほなblog.urls
をつくってくで」
touch todo/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.todo_list, name='todo_list'),
]
ワイ「これでlocalhost:8000/
へのアクセスはtodo_list.html
にリダイレクトされるな」
viewをつくる
ワイ「さっきblog.urls
で指定したview.todo_list
の部分を実装するで」
from django.shortcuts import render
def todo_list(request):
return render(request, 'todo/todo_list.html', {})
ワイ「書いてることは単純やな」
ワイ「render
っていうテンプレをもとにviewを作る関数を呼び出して」
ワイ「その中であれこれ組み立ててできた値を戻り値にするで」
ワイ「詳しい話はまた今度や、今回は雰囲気だけ掴むで」
いざ確認
ワイ「とりあえずこんなもんやろか」
ワイ「完了したら localhost:8000 にアクセスや」
ワイ「こんにちは、世界、ってな」
??・閲覧者「やかましいわ」
登録したTodoをテンプレートに渡してみる(Django ORM)
ワイ「Todoアプリやしとりあえず登録したTodoの確認から始めてみるで」
ワイ「ここでデータ登録してない人はなんでもええから登録してな」
ワイ「まずはちゃんとデータが取れるか確認するで」
docker-compose exec web python manage.py shell
// 対話モードに入る
// 行ごとに入力・エンターキーを押してください
>>> from todo.models import Todo
>>> Todo.objects.all()
<QuerySet [<Todo: sample>]>
ワイ「大丈夫そうやな」
ワイ「ほな実際にロジックとして書いていくで」
from django.shortcuts import render
from .models import Todo
def todo_list(request):
todos = Todo.objects.all()
return render(request, 'todo/todo_list.html', {'todo': todos})
渡されたデータを表示する
ワイ「Djangoやとテンプレートタグってのがあるんか」
以下djangogirlsより
テンプレートタグとは?
HTML中で本当はPythonのコードを書くことはできません。なぜならブラウザが理解できないからです。ブラウザはHTMLだけ分かります。HTMLはどちらかというと静的で、それに対してPythonはもっとずっと動的なことを私たちは知っています。
Djangoテンプレートタグ はHTMLにPyhtonのようなコードを埋め込むことができて、動的なウェブサイトがより早く簡単に作れます!
ワイ「だそうや」
ワイ「ほな書いてくで」
<html>
<head>
<title>todo</title>
</head>
<body>
<h1>hello world</h1>
{{ todo }} // 追記部分
</body>
</html>
ワイ「こんな感じで{{ 渡したデータ }}
で書けるみたいやな」
ワイ「ほなアクセスアクセス〜」
locahost:8000
ワイ「さっきの対話モードとおんなじ表記やな」
ワイ「これはリストやからループでええ感じに取り出せそうやな」
<html>
<head>
<title>todo</title>
</head>
<body>
<h1>hello world</h1>
{% for td in todo %}
<div>
<p>タスク名:{{ td.title}}</p>
<p>タスク内容:{{ td.description}}</p>
</div>
{% endfor %}
</body>
</html>
ワイ「リストの中身はmodels
で登録したテーブルのカラムやからこんな感じでええやろ」
ワイ「ほな確(ry」
localhost:8000
ワイ「ええやん」
CSSで可愛くオシャレしよう
ワイ「とりあえずデータは表示したけど」
ワイ「見辛いし味気ないな」
ワイ「ここはcssちゃんでちょちょいのちょいや」
ワイ「・・・と言うとでも思ったか」
ワイ「ワイはtailwindcss
ちゃん単推しや!!!!」
ワイ「ちなみに普通のcss書く場合はここを参考にしてな」
ワイ「さっそく書いてくで」
<html>
<head>
<title>todo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<h1 class="text-red-500 text-5xl mb-5">hello world</h1>
<div class="mx-auto w-9/12">
{% for td in todo %}
<div class="border-4 p-8">
<p class="text-2xl border-b-2 mb-2">タスク名:{{ td.title}}</p>
<p>タスク内容:{{ td.description}}</p>
</div>
{% endfor %}
</div>
</body>
</html>
ワイ「こんな感じや」
localhsot:8000
ワイ「完璧やな!ええデザインや」
ワイくんは・・・
ワイ「とりあえずこんなもんでええか」
ワイ「今日はもう疲れてもたわ」
ワイ「次はこの画面で登録したり消したりできるようにするで〜」
最後に
前回に引き続き拙い文章+長編となってしまいましたがここまでお読み頂きありがとうございました。
また、前回の記事に関しても少なからず反響を頂けまして記事にした甲斐があったと共に、反省もしております。
時間を見つけて記事の修正予定ですのでお許しください。
何か問題点等ありましたらお気軽にコメント、もしくはTwitterの方へ連絡頂けますと幸いです。
今回は一通りDjangoの機能に触れながらデータベースの情報を表示するところまで進めました。
次回はワイくんも言っていた通り
- 登録機能
- 削除機能
デザインの改修
の三本立ての予定です。
ではまた次回。