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

如何在Django项目中将图片存到Amazon S3、视频存到Vimeo

解决Django中视频上传至Vimeo而图片存S3的问题

嘿,我懂你遇到的困境——upload_to确实没法拿到文件的绝对路径,因为这个方法触发时文件还没完成持久化(可能还在内存里或者临时缓存)。别慌,咱们换个思路,用自定义存储类或者模型save方法重写就能完美解决这个需求,下面给你两种可行的方案:

方案一:重写模型的save方法(灵活易控)

这种方式先把视频临时存在S3(或者本地),然后在保存模型时调用Vimeo API上传,最后替换成Vimeo的链接并清理临时文件。

步骤1:安装Vimeo Python SDK

pip install vimeo

步骤2:配置Vimeo API密钥(settings.py)

# Vimeo API配置,去Vimeo开发者后台获取
VIMEO_CLIENT_ID = "你的客户端ID"
VIMEO_CLIENT_SECRET = "你的客户端密钥"
VIMEO_ACCESS_TOKEN = "你的访问令牌"

步骤3:编写模型逻辑

from django.db import models
from django.conf import settings
from django.core.files.base import ContentFile
import vimeo
from storages.backends.s3boto3 import S3Boto3Storage

class MediaModel(models.Model):
    # 图片直接存S3
    image = models.ImageField(storage=S3Boto3Storage(), upload_to="images/%Y/%m/%d/")
    # 视频先临时存S3,后续上传Vimeo后会清空
    temp_video = models.FileField(upload_to="temp_videos/%Y/%m/%d/", blank=True, null=True)
    # 存储Vimeo的视频链接
    vimeo_url = models.URLField(blank=True, null=True)

    def save(self, *args, **kwargs):
        # 只有当有新视频且还没上传到Vimeo时处理
        if self.temp_video and not self.vimeo_url:
            # 初始化Vimeo客户端
            vimeo_client = vimeo.VimeoClient(
                token=settings.VIMEO_ACCESS_TOKEN,
                key=settings.VIMEO_CLIENT_ID,
                secret=settings.VIMEO_CLIENT_SECRET
            )

            try:
                # 读取临时视频文件内容
                with self.temp_video.open("rb") as f:
                    video_content = ContentFile(f.read())
                    # 上传到Vimeo(大文件可以用upload_large方法)
                    upload_response = vimeo_client.upload(
                        data=video_content,
                        name=self.temp_video.name,
                        description="从Django项目上传的视频"
                    )

                # 获取Vimeo视频的详情和链接
                video_uri = upload_response.headers["Location"]
                video_info = vimeo_client.get(video_uri).json()
                self.vimeo_url = video_info["link"]  # 或者用player_embed_url获取嵌入链接

                # 清理临时文件和字段
                self.temp_video.delete(save=False)
                self.temp_video = None
            except Exception as e:
                # 上传失败时可以抛出错误或者做降级处理
                raise RuntimeError(f"Vimeo上传失败: {str(e)}")

        super().save(*args, **kwargs)

方案二:自定义Vimeo存储类(更优雅的Django风格)

直接给视频字段指定自定义存储类,让Django在处理文件上传时自动调用Vimeo API,无需临时存储。

步骤1:编写自定义存储类

from django.core.files.storage import Storage
from django.conf import settings
import vimeo

class VimeoStorage(Storage):
    def _open(self, name, mode="rb"):
        # 不需要从Vimeo读取文件到Django,直接抛出异常
        raise NotImplementedError("VimeoStorage不支持打开文件")

    def _save(self, name, content):
        # 核心:把文件内容上传到Vimeo
        vimeo_client = vimeo.VimeoClient(
            token=settings.VIMEO_ACCESS_TOKEN,
            key=settings.VIMEO_CLIENT_ID,
            secret=settings.VIMEO_CLIENT_SECRET
        )

        upload_response = vimeo_client.upload(
            data=content,
            name=name,
            description="通过VimeoStorage上传的视频"
        )

        video_uri = upload_response.headers["Location"]
        video_info = vimeo_client.get(video_uri).json()
        # 返回Vimeo的视频链接作为存储的"文件名"
        return video_info["link"]

    def exists(self, name):
        # 简化处理:默认不存在重复视频,每次都新上传
        return False

    def url(self, name):
        # 因为name已经是Vimeo的链接,直接返回
        return name

步骤2:在模型中使用

from django.db import models
from storages.backends.s3boto3 import S3Boto3Storage
from .storage import VimeoStorage

class MediaModel(models.Model):
    image = models.ImageField(storage=S3Boto3Storage(), upload_to="images/%Y/%m/%d/")
    # 视频直接用VimeoStorage
    video = models.FileField(storage=VimeoStorage(), upload_to="videos/")

注意事项

  • 大文件上传:如果视频超过1GB,建议用Vimeo SDK的upload_large方法实现分块上传,避免超时。
  • 错误处理:记得给API调用加try-except块,处理网络异常、权限不足等情况。
  • Vimeo权限:确保你的Access Token拥有create和edit视频的权限,去Vimeo开发者后台配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:28:53