You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Django REST Framework中实现图片上传与服务功能?

嘿,我来帮你搞定DRF通用视图结合图片上传的问题!其实这事儿没那么复杂,咱们一步步拆解来做:

第一步:定义带图片字段的模型

首先得有个存储图片的模型,用ImageField指定上传路径就行,记得先装Pillow处理图片哦:

# your_app/models.py
from django.db import models

class Image(models.Model):
    title = models.CharField(max_length=100, help_text="给图片加个标题吧")
    image = models.ImageField(upload_to='uploads/images/%Y/%m/%d/')  # 按年月分类存储,更整洁
    uploaded_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.title} - {self.uploaded_at.strftime('%Y-%m-%d')}"

然后安装依赖:

pip install pillow

还要在项目的settings.py里配置媒体文件的存储路径和访问URL:

# settings.py
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# 媒体文件配置
MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'

最后在项目根路由里加媒体文件的访问路由(开发环境用,生产环境别这么搞):

# project/urls.py
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('your_app.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
第二步:创建序列化器

序列化器要能处理文件上传,还能返回图片的完整访问URL,这样前端直接就能用:

# your_app/serializers.py
from rest_framework import serializers
from .models import Image

class ImageSerializer(serializers.ModelSerializer):
    # 自定义字段返回完整图片URL
    image_url = serializers.SerializerMethodField()

    class Meta:
        model = Image
        fields = ['id', 'title', 'image', 'image_url', 'uploaded_at']

    def get_image_url(self, obj):
        # 从上下文里拿request,用来生成绝对URL
        request = self.context.get('request')
        if obj.image and request:
            return request.build_absolute_uri(obj.image.url)
        return obj.image.url if obj.image else None

    # 可选:添加图片验证,限制大小和格式
    def validate_image(self, value):
        # 限制2MB以内
        if value.size > 2 * 1024 * 1024:
            raise serializers.ValidationError("图片大小不能超过2MB哦")
        # 只允许图片格式
        allowed_types = ['image/jpeg', 'image/png', 'image/webp']
        if value.content_type not in allowed_types:
            raise serializers.ValidationError("只能上传JPG、PNG或WebP格式的图片")
        return value
第三步:用通用视图实现上传+服务功能

这里推荐用ModelViewSet,一次搞定上传、列表、详情、更新、删除所有功能,比单独写多个通用视图省事多了:

# your_app/views.py
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated  # 可选:权限控制
from .models import Image
from .serializers import ImageSerializer

class ImageViewSet(viewsets.ModelViewSet):
    queryset = Image.objects.all().order_by('-uploaded_at')  # 按上传时间倒序
    serializer_class = ImageSerializer
    # 可选:只有登录用户才能操作,注释掉就是公开访问
    # permission_classes = [IsAuthenticated]

    # 把request传到序列化器的上下文里,用来生成绝对URL
    def get_serializer_context(self):
        context = super().get_serializer_context()
        context['request'] = self.request
        return context

然后在app的路由里注册这个ViewSet:

# your_app/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ImageViewSet

router = DefaultRouter()
router.register(r'images', ImageViewSet, basename='image')

urlpatterns = [
    path('', include(router.urls)),
]

这样你就拥有了这些API接口:

  • POST /api/images/:上传图片(form-data格式,传title和image字段)
  • GET /api/images/:获取所有图片列表(带完整image_url)
  • GET /api/images/<id>/:获取单张图片的详情
  • PUT/PATCH /api/images/<id>/:更新图片的标题或替换图片
  • DELETE /api/images/<id>/:删除图片

如果只需要部分功能,比如只上传和列表,也可以单独用通用视图:

# 示例:单独用CreateAPIView和ListAPIView
from rest_framework.generics import CreateAPIView, ListAPIView

class ImageUploadView(CreateAPIView):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer

    def get_serializer_context(self):
        return {'request': self.request}

class ImageListView(ListAPIView):
    queryset = Image.objects.all().order_by('-uploaded_at')
    serializer_class = ImageSerializer

    def get_serializer_context(self):
        return {'request': self.request}

对应的路由改成:

urlpatterns = [
    path('images/upload/', ImageUploadView.as_view(), name='image-upload'),
    path('images/', ImageListView.as_view(), name='image-list'),
]
第四步:测试一下

直接用DRF自带的可视化界面访问http://localhost:8000/api/images/,就能上传图片、查看列表了。或者用curl命令测试上传:

curl -X POST -H "Content-Type: multipart/form-data" -F "title=我的风景照" -F "image=@/Users/me/Desktop/photo.jpg" http://localhost:8000/api/images/
生产环境注意事项
  • 别用static()处理媒体文件,用Nginx或Apache配置静态资源服务
  • 可以用第三方存储服务,比如阿里云OSS、AWS S3,Django有对应的库支持
  • 记得给MEDIA_ROOT目录设置正确的读写权限

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

火山引擎 最新活动