djangoで、独自管理画面を作ってみる。
djangoは管理画面が最初からついているけど、phpmyadminみたいにモデル(テーブル)単位のCRUDなので
Webアプリの管理画面としては、あまり使えない。
1 2 3 4 5 |
# djangoプロジェクト生成 django-admin startproject AdminPanelproject # myappアプリ(機能)を生成 python manage.py startapp myapp |
myproject/settings.py に作ったアプリを追加
1 2 3 4 |
INSTALLED_APPS = [ ... 'myapp', ] |
myapp/models.pyに、モデル(テーブル)定義を書く。コースと動画URL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from django.db import models class Course(models.Model): title = models.CharField(max_length=255) def __str__(self): return self.title class Video(models.Model): title = models.CharField(max_length=255) youtube_url = models.URLField() # djangoだと親がhasmany指定するじゃなくて、子が親に対してForeignKey(1:n)指定する(自動で逆参照が生える) # 複数の親コースに所属させるには、ManyToMany(n:n)にする courses = models.ManyToManyField(Course) def __str__(self): return self.title |
DB生成
1 2 3 4 5 6 7 |
# マイグレーションファイル(テーブル定義)生成 python manage.py makemigrations # DBに反映 python manage.py migrate # 管理者ユーザ作成 python manage.py createsuperuser |
myproject/urls.py にルーティングを追加。
1 2 3 4 5 6 7 8 |
from django.contrib import admin from django.urls import path, include # include追加 urlpatterns = [ # path('admin/', admin.site.urls), path('admin/', include('myapp.urls')), # admin以下はmyappにルーティング ] |
myapp/urls.py を /admin/ 専用に作る
1 2 3 4 5 6 7 8 9 |
from django.urls import path from . import views urlpatterns = [ path('', views.dashboard, name='dashboard'), # /admin/ path('videos/', views.video_list, name='video_list'), # /admin/videos/ path('videos/create/', views.video_create, name='video_create'), # 追加する場合 path('courses/', views.course_list, name='course_list'), # /admin/courses/ ] |
myapp/views.pyで、ビューを作る(laravel的にはルーティング)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
from django.shortcuts import render, redirect from .models import Course, Video def dashboard(request): return render(request, 'admin/dashboard.html') def course_list(request): courses = Course.objects.all() return render(request, 'admin/course_list.html', {'courses': courses}) def video_list(request): videos = Video.objects.all() return render(request, 'admin/video_list.html', {'videos': videos}) def video_create(request): courses = Course.objects.all() if request.method == 'POST': title = request.POST['title'] youtube_url = request.POST['youtube_url'] course_id = request.POST['course'] course = Course.objects.get(id=course_id) Video.objects.create(title=title, youtube_url=youtube_url, course=course) return redirect('video_list') return render(request, 'admin/video_create.html', {'courses': courses}) |
myapp/templates/admin/ でHTMLテンプレートを作成する
1 2 3 4 5 6 7 8 9 10 11 12 |
myproject/ ├─ myapp/ │ ├─ templates/ │ │ ├─ admin/ │ │ │ ├─ dashboard.html │ │ │ ├─ course_list.html │ │ │ ├─ video_list.html │ │ │ ├─ video_create.html │ ├─ views.py │ ├─ urls.py │ ├─ models.py ├─ myproject/(settings.py など) |
seedで、あらかじめDBにレコードを入れておく
myapp/management/commands/seed.pyを作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from django.core.management.base import BaseCommand from myapp.models import Course, Video class Command(BaseCommand): help = 'サンプルデータを投入する' def handle(self, *args, **kwargs): course1 = Course.objects.create(title="Django 入門") course2 = Course.objects.create(title="YouTube 活用講座") video1 = Video.objects.create(title="Django 設計", youtube_url="https://youtube.com/watch?v=xxx") video2 = Video.objects.create(title="Django テンプレート", youtube_url="https://youtube.com/watch?v=yyy") video1.courses.add(course1) video2.courses.add(course1, course2) self.stdout.write(self.style.SUCCESS('シードデータを作成しました!')) |
1 2 3 4 5 |
# レコード生成 python manage.py seed 簡易Webサーバで確認 python manage.py runserver |
一般ユーザ向けページが無いので追加。
myproject/urls.py
1 2 3 4 5 6 7 |
urlpatterns = [ # path('admin/', admin.site.urls), path('admin/', include('myapp.urls')), # admin以下はmyappにルーティング path('', front_views.index, name='index'), path('courses/', front_views.course_list, name='front_course_list'), path('courses/<int:pk>/', front_views.course_detail, name='front_course_detail'), ] |
URL 設定(一般ユーザー用)
myapp/front_urls.py
1 2 3 4 5 6 7 8 |
from django.urls import path from . import front_views urlpatterns = [ path('', front_views.index, name='index'), path('courses/', front_views.course_list, name='front_course_list'), path('courses/<int:pk>/', front_views.course_detail, name='front_course_detail'), ] |
myapp/front_views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from django.shortcuts import render, get_object_or_404 from .models import Course def index(request): return render(request, 'front/index.html') def course_list(request): courses = Course.objects.all() return render(request, 'front/course_list.html', {'courses': courses}) def course_detail(request, pk): course = get_object_or_404(Course, pk=pk) videos = course.video_set.all() # ForeignKey の場合 # ManyToMany の場合は↓ # videos = course.video_set.all() は自動でできないので related_name を設定するのがベター # 例: videos = course.videos.all() return render(request, 'front/course_detail.html', { 'course': course, 'videos': videos }) |
myapp/templates/front/index.html
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>トップページ</title> </head> <body> <h1>ようこそ!</h1> <p>このサイトでは、コースと動画を閲覧できます。</p> <p><a href="{% url 'front_course_list' %}">コース一覧を見る</a></p> </body> </html> |
myapp/templates/front/course_list.html
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<h1>コース一覧</h1> <ul> {% for course in courses %} <li> <a href="{% url 'front_course_detail' course.pk %}"> {{ course.title }} </a> </li> {% empty %} <li>コースがありません</li> {% endfor %} </ul> <a href="{% url 'index' %}">← トップページに戻る</a> |
myapp/templates/front/course_detail.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<h1>{{ course.title }}</h1> <h2>動画一覧</h2> <ul> {% for video in videos %} <li> {{ video.title }} <a href="{{ video.youtube_url }}" target="_blank">YouTubeで見る</a> </li> {% empty %} <li>動画がありません</li> {% endfor %} </ul> <a href="{% url 'front_course_list' %}">← コース一覧に戻る</a> |