You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django搭建YouTube克隆项目:首页视频缩略图无法加载求助

Django YouTube克隆项目缩略图无法显示问题

问题描述

我是Django新手,正在搭建YouTube克隆项目以深入掌握Django技术。启动服务器后,首页无法显示视频缩略图,已尝试多种方法仍未解决。

相关代码与信息

1) 模板文件

homeview.html

{% block body %}
{% for video in most_recent_video %}
<div class="video-card">
  <img src="/get_thumbnail/{{ video.thumbnail.path }}" alt="{{ video.title }} thumbnail">
  <h5>{{ video.title }}</h5>
  <p>Uploaded By {{ video.user }} on {{ video.datetime }}</p>
  <p>{{ video.description }}</p>
  <p><a href="/video/{{ video.id }}">Watch Video</a></p>
</div>
{% endfor %}
{% endblock %}

thumbnail.html

{% block body %}

    <div class="header-bar">
        <h2>Thumbnail View</h2>
        <hr>
    </div>

    <div class="main-body">
        <form method="POST" enctype="multipart/form-data">
            {% csrf_token %}
            <table>
                {{ form.as_p }}
            </table>
            <button type="submit">Upload Thumbnail</button>
        </form>
        
        {% if errors %}
            <div class="errors">
                <h3>Errors:</h3>
                <ul>
                    {% for field_errors in errors.values %}
                        {% for error in field_errors %}
                            <li>{{ error }}</li>
                        {% endfor %}
                    {% endfor %}
                </ul>
            </div>
        {% endif %}
    </div>

{% endblock %}

2) views.py

class ThumbnailView(View):
    template_name = 'base/thumbnail.html'

    def get(self, request):
        if not request.user.is_authenticated:
            return HttpResponseRedirect('/login/')

        form = ThumbNailForm()
        return render(request, self.template_name, {'form': form})

    def post(self, request):
        form = ThumbNailForm(request.POST, request.FILES)

        if form.is_valid():
            # Create a new Thumbnail entry
            title = form.cleaned_data['title']
            thumbnail_file = form.cleaned_data['file']

            # Generate a random filename for the thumbnail
            random_chars = ''.join(random.choices(
                string.ascii_uppercase + string.digits, k=10))
            filename = random_chars + thumbnail_file.name

            # Save the thumbnail file
            BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            thumbnail_path = os.path.join(BASE_DIR, filename)
            with open(thumbnail_path, 'wb') as f:
                f.write(thumbnail_file.read())

            thumbnail = Thumbnail(title=title, path=filename)
            thumbnail.save()

            return HttpResponseRedirect('/home/')
        else:
            return render(request, self.template_name, {'form': form, 'errors': form.errors})

class ThumbnailFileView(View):

    def get(self, request, file_name):
        BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        stripped_file_name = file_name[10:] 
        file = FileWrapper(open(os.path.join(BASE_DIR, stripped_file_name), 'rb'))
        response = HttpResponse(file, content_type='image/jpg')
        response['Content-Disposition'] = 'attachment; filename={}'.format(stripped_file_name)
        return response

3) urls.py

path('get_thumbnail/<file_name>', ThumbnailFileView.as_view(), name='getthumbnail'),
path('thumbnail/', ThumbnailView.as_view(), name='thumbnail'),

4) models.py

class Video(models.Model):
    title = models.CharField(max_length=30)
    description = models.TextField(max_length=300)
    path = models.CharField(max_length=100)
    datetime = models.DateTimeField(auto_now=True ,blank=False, null=False)
    user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    likes = models.IntegerField(default=0)
    dislikes = models.IntegerField(default=0)
class Thumbnail(models.Model):
     title = models.CharField(max_length=50)
     path = models.CharField(max_length=100)

class ThumbnailView(models.Model):
     image = models.ForeignKey(Video, on_delete=models.CASCADE, related_name='thumbnails')

5) forms.py

class ThumbNailForm(forms.Form):
    title = forms.CharField(label='Title', max_length=50)
    file = forms.FileField()

6) 控制台错误信息

<QuerySet [<Video: Video object (43)>, <Video: Video object (42)>, <Video: Video object (41)>, <Video: Video object (40)>, <Video: Video object (39)>, <Video: Video object (38)>, <Video: Video object (37)>, <Video: Video object (36)>, <Video: Video object (35)>]>
[01/Apr/2023 15:44:21] "GET /home/ HTTP/1.1" 200 16180
Not Found: /get_thumbnail/
[01/Apr/2023 15:44:21] "GET /get_thumbnail/ HTTP/1.1" 404 13168

7) 图片路径

C:\Users\Admin\Desktop\Youtube Redesign\Config\img1.jpg
C:\Users\Admin\Desktop\Youtube Redesign\Config\img2.jpg
C:\Users\Admin\Desktop\Youtube Redesign\Config\img3.jpg

问题分析与解决步骤

1. 模型关联缺失导致模板变量为空

控制台显示请求/get_thumbnail/无文件名,说明video.thumbnail.path为空。当前Video模型未与Thumbnail建立关联,模板中video.thumbnail不存在,导致URL拼接错误。

修复方法:
修改Video模型,添加缩略图外键关联,同时删除无用的ThumbnailView模型:

class Video(models.Model):
    title = models.CharField(max_length=30)
    description = models.TextField(max_length=300)
    path = models.CharField(max_length=100)
    datetime = models.DateTimeField(auto_now=True ,blank=False, null=False)
    user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    likes = models.IntegerField(default=0)
    dislikes = models.IntegerField(default=0)
    # 添加缩略图关联
    thumbnail = models.ForeignKey(Thumbnail, on_delete=models.SET_NULL, null=True, blank=True)

class Thumbnail(models.Model):
     title = models.CharField(max_length=50)
     path = models.CharField(max_length=100)

2. 文件存储与读取路径不匹配

你将缩略图保存在项目根目录,且在ThumbnailFileView中错误截取文件名前10位,导致文件找不到。同时未遵循Django媒体文件规范。

修复方法:

  • 在项目settings.py中配置媒体文件:
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

创建项目根目录下的media文件夹。

  • 修改ThumbnailView的post方法,将文件保存到MEDIA_ROOT:
from django.conf import settings

def post(self, request):
    form = ThumbNailForm(request.POST, request.FILES)
    if form.is_valid():
        title = form.cleaned_data['title']
        thumbnail_file = form.cleaned_data['file']
        random_chars = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
        filename = random_chars + thumbnail_file.name
        # 保存到media目录
        file_path = os.path.join(settings.MEDIA_ROOT, filename)
        with open(file_path, 'wb') as f:
            f.write(thumbnail_file.read())
        thumbnail = Thumbnail(title=title, path=filename)
        thumbnail.save()
        # 补充:需关联到对应Video,可在表单添加视频选择字段或调整上传逻辑
        return HttpResponseRedirect('/home/')
    else:
        return render(request, self.template_name, {'form': form, 'errors': form.errors})
  • 修改ThumbnailFileView,直接读取媒体目录文件,取消文件名截取:
from django.conf import settings
from django.http import HttpResponseNotFound

class ThumbnailFileView(View):
    def get(self, request, file_name):
        file_path = os.path.join(settings.MEDIA_ROOT, file_name)
        if not os.path.exists(file_path):
            return HttpResponseNotFound("Thumbnail not found")
        file = FileWrapper(open(file_path, 'rb'))
        response = HttpResponse(file, content_type='image/jpeg')
        # 改为inline让图片直接显示,而非下载
        response['Content-Disposition'] = 'inline; filename={}'.format(file_name)
        return response

3. URL路由参数格式错误

Django 2+需指定参数类型,否则无法正确匹配。修改urls.py:

path('get_thumbnail/<str:file_name>', ThumbnailFileView.as_view(), name='getthumbnail'),

4. 模板URL生成优化

使用Django的url标签生成正确URL,避免硬编码:

<img src="{% url 'getthumbnail' video.thumbnail.path %}" alt="{{ video.title }} thumbnail">

内容的提问来源于stack exchange,提问作者Salman Naqvi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 15:25:07