🐍

【Python】Djangoでデーベースの内容をビューに表示する

2024/11/20に公開

開発環境:

項目 バージョン
windows 11
Vscode 1.87.2
Docker 26.1.1
Docker-compose 2.27.0
python 3.11.10
Django 5.0.1
Psql 16.5

達成目標

  • データベース上に登録されている動画ファイルの内容をビューで一覧表示させることができる。

前提

  • DjangoのマニュアルのWriting your first Django app, part 1を応用した内容となっている。
  • アプリケーションのトップページが表示されている状態かつデータベースの設定が完了している状態から解説をしていく。

https://docs.djangoproject.com/en/5.1/intro/tutorial01/

開発環境の構築がまだの方はこちらから↓

https://zenn.dev/code_journey_ys/articles/ddd8ba305a2538

データベースの設定がまたの方はこちらから↓

https://zenn.dev/code_journey_ys/articles/50df0fe110baac

基礎編

1.アプリケーションフォルダを作成する

アプリケーションフォルダ作成コマンドの実行

アプリケーションフォルダの作成コマンドを実行
docker-compose exec web python manage.py startapp videos


videosアプリケーションフォルダが作成される

プロジェクトフォルダ内のsettings.pyへの追加

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'users',
    'videos', # 追加
]

2.モデルの作成

動画に関わる情報をmodels.pyファイルに追加
from django.db import models
from django.contrib.auth.models import User

class Video(models.Model):
    title = models.CharField(max_length=200)  # 動画のタイトル
    description = models.TextField(blank=True, null=True)  # 動画の説明
    video_file = models.FileField(upload_to='videos/', blank=True, null=True)  # 動画ファイルを保存
    created_at = models.DateTimeField(auto_now_add=True)  # 登録日
    category = models.CharField(max_length=100, blank=True, null=True)  # 動画のカテゴリー
    thumbnail = models.ImageField(upload_to='thumbnails/', blank=True, null=True)  # サムネイル画像
    duration = models.PositiveIntegerField(blank=True, null=True)  # 動画の長さ(秒単位)
    is_published = models.BooleanField(default=True)  # 公開状態
    uploaded_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)  # アップロードしたユーザー
    view_count = models.PositiveIntegerField(default=0)  # 視聴回数
    rating = models.PositiveIntegerField(default=0)  # 動画の評価
    updated_at = models.DateTimeField(auto_now=True)  # 最終更新日
    published_at = models.DateTimeField(null=True, blank=True)  # 公開日

    def __str__(self):
        return self.title

3.マイグレーションの実行

マイグレーションの実行
docker-compose exec web python manage.py makemigrations videos
docker-compose exec web python manage.py migrate videos 
出力結果
$ docker-compose exec web python manage.py makemigrations videos
time="2024-11-20T22:42:21+09:00" level=warning msg="C:\\Users\\shimo\\Desktop\\test\\reha_navi\\docker-compose.yml: `version` is obsolete"
Migrations for 'videos':
  videos/migrations/0001_initial.py
    - Create model Video
$ docker-compose exec web python manage.py migrate videos 
Operations to perform:
  Apply all migrations: videos
Running migrations:
  Applying videos.0001_initial... OK

4.管理画面(python admin)への追加

admin.pyへ以下を全て追加
from .models import Video

class VideoAdmin(admin.ModelAdmin):
    list_display = ('title', 'category', 'created_at', 'is_published', 'uploaded_by', 'view_count', 'rating', 'published_at')
    list_filter = ('is_published', 'category', 'created_at')
    search_fields = ('title', 'description', 'category')
    ordering = ('-created_at',)
    date_hierarchy = 'created_at'

admin.site.register(Video, VideoAdmin)

5.ビューの作成

urls.pyファイルの作成

urls.pyファイルの作成
New-Item videos/urls.py

urls.pyファイルの編集

urls.pyへ以下を全て追加
from django.urls import path
from . import views

urlpatterns = [
    path('', views.video_list, name='video_list'),
    path('video/<int:id>/', views.video_detail, name='video_detail'),
]

views.pyファイルの編集

views.pyへ以下を全て追加
from django.shortcuts import render, get_object_or_404
from .models import Video

def video_list(request):
    videos = Video.objects.filter(is_published=True).order_by('-created_at')  # 公開されている動画を降順で取得
    return render(request, 'videos/video_list.html', {'videos': videos})

def video_detail(request, id):
    video = get_object_or_404(Video, id=id)
    return render(request, 'videos/video_detail.html', {'video': video})

6.テンプレートの作成

フォルダの作成

テンプレートフォルダの作成
mkdir videos/templates/videos

ファイルの作成

テンプレートファイルの作成
New-Item videos/templates/videos/video_list.html
New-Item videos/templates/videos/video_detail.html

ファイルの編集

video_list.htmlへ以下を全て追加
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>動画一覧</title>
    <style>
        /* コンテナの設定 */
        .video-list {
            display: flex;
            flex-wrap: wrap; /* 複数行に対応 */
            gap: 20px; /* カード間の間隔 */
            justify-content: center; /* 中央揃え */
            padding: 20px;
            list-style-type: none; /* リストスタイルを削除 */
        }

        /* 各動画カードの設定 */
        .video-card {
            width: 320px; /* カードの幅 */
            border: 1px solid #ddd; /* ボーダー */
            border-radius: 8px; /* 角丸 */
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); /* シャドウ */
            overflow: hidden; /* 内容がはみ出ないようにする */
            text-align: center;
            background-color: #fff;
        }

        /* カード内のサムネイル画像 */
        .video-card img {
            width: 100%; /* カード幅に合わせる */
            height: auto;
            max-height: 200px; /* 画像の最大高さ */
            object-fit: cover; /* 画像の縦横比を維持しつつ、領域に収める */
        }

        /* カード内のタイトル */
        .video-card h3 {
            font-size: 18px;
            margin: 10px 0;
        }

        /* カード内の説明文 */
        .video-card p {
            font-size: 14px;
            color: #666;
            padding: 0 10px 10px;
            margin: 0;
        }

        /* カード内の動画再生エリア */
        .video-card video {
            width: 100%; /* カード幅に合わせる */
            margin-top: 10px; /* 動画の上にスペースを追加 */
        }
    </style>
</head>
<body>
    <h1 style="text-align: center;">動画一覧</h1>
    <ul class="video-list">
        {% for video in videos %}
        <li class="video-card">
            {% if video.thumbnail %}
                <img src="{{ video.thumbnail.url }}" alt="{{ video.title }}">
            {% endif %}

            <!-- 動画ファイルを再生 -->
            {% if video.video_file %}
                <video controls>
                    <source src="{{ video.video_file.url }}" type="video/mp4">
                    お使いのブラウザは動画再生に対応していません。
                </video>
            {% endif %}

            <h3>{{ video.title }}</h3>
            <p>{{ video.description }}</p>
        </li>
        {% endfor %}
    </ul>
</body>
</html>
video_detail.htmlへ以下を全て追加
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ video.title }}</title>
</head>
<body>
    <h1>{{ video.title }}</h1>
    <p>{{ video.description }}</p>
    <p>カテゴリ: {{ video.category }}</p>
    <p>視聴回数: {{ video.view_count }} 回</p>
    <p>評価: {{ video.rating }} 点</p>
    <p>公開日: {{ video.published_at }}</p>
    <p>アップロード者: {{ video.uploaded_by.username }}</p>
    <a href="{% url 'video_list' %}">戻る</a>
</body>
</html>

7.プロジェクトのurls.pyにインクルード

urls.pyにインクルードとif settings~を追加
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('videos/', include('videos.urls')), # 追加
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

8.データの追加

Django adminから動画のデータを追加する

9.表示を確認

http://localhost:8000/videos/へアクセスし、表示を確認する

http://localhost:8000/videos/video/1/へアクセスし、表示を確認する

Discussion