Django图片的上传与访问

1,326 阅读3分钟

1.实现目标

目标在于实现两个视图,其中一个视图能上传图片到服务器,其中一个能访问服务器中的图片路径,以此来模拟用户头像的上传与访问。

2.数据库 & 序列化器的实现

模型类User

# mdoels.py

from django.db import models

# 用户类
class User(models.Model):
    ...
    # 在这里只关注用户的头像类型 
    """
        ImageField中的 up_load一定要配置,代表你最后的图片
        会存储到MEDIA_ROOT/up_load(实际上是你赋予的名称)这个文件夹中。
    """
    user_header = models.ImageField(upload_to='user_headers/')

序列化器(只序列化id和头像)UserHeaderSerializer:

# serializers.py

from .models import User
class UserHeaderSerializer(ModelSerializer):
    class Meta:
        model = User
        fields = ["id","user_header"]

3.图片的上传接口 & 配置图片保存位置

配置MEDIA_ROOT:

# settings.py

BASE_DIR = Path(__file__).resolve().parent.parent
"""
通过配置 MEDIA_ROOT ,这样的话据可以指定用户模型的ImageField字段的保存位置指定为:
    MEDIA_ROOT/up_load

在本案路中:
    此时的 MEDIA_ROOT 为:              项目根目录/media
    upload 在 models.py 中被指定为:    'user_headers/'
    那么图片将会被保存在:              项目根目录/media/user_headers/
"""
MEDIA_ROOT=  os.path.join(BASE_DIR,'media')

图片的上传视图:

# user/views.py

class UserHeaders(APIView):
    def put(self,request,pk):
        user = User.objects.get(id = pk)
        """ 
            这里进行序列化的同时就对头像图片进行了保存 ,保存位置为:
                项目根目录/media/user_headers/???.*
                
            而在数据库中的 user_header字段 则保存 upload指定的字段,即:
                user_header/???.*
        """
        serializer = UserHeaderSerializer(instance=user,data=request.data)
        try:
            # 验证并保存
            serializer.is_valid(raise_exception=True)
            serializer.save()
        except ValidationError:
            return Response({"msg":serializer.errors})
        return Response({"msg":"用户头像上传成功"})

url配置:

# user/urls.py

re_path('^userheaders/(?P<pk>\d+)$',views.UserHeaders.as_view())

使用postman进行测试:

image.png

最终图片保存成功:

image.png

image.png

4.图片的访问接口 & 配置文件访问

进行 MEDIA_URL 配置

#settings.py
""" 配置MEDIA_URL是为了让客户端直接访问media中的数据,类似于STATIC_URL """
MEDIA_URL = '/media/'

主路由配置:

# 主urls.py

from django.contrib import admin
from django.views.static import serve
from django.conf import settings
from django.urls import path,re_path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('user.urls')),
    
    """ 配置如下:需要用到之前配置的 MEDIA_ROOT """
    re_path(r'^media/(?P<path>.*)$',serve,{
        'document_root':settings.MEDIA_ROOT
    })
]

配置完后就可以在浏览器访问 127.0.0.1:8000/media/...以下的静态文件

下面实现访问视图:
注意:访问视图与上传视图在同一个类里面

# user/views.py

from .models import User
from .serializers import UserSerializer,UserHeaderSerializer

class UserHeaders(APIView):
    def get(self,request,pk):
        user = User.objects.get(id = pk) # 找到哪个用户正在访问
        serializer = UserHeaderSerializer(instance=user)
        
        update_serializer_data = serializer.data
        """
            这里应该让返回的数据为:
                我的服务器地址 +  序列化后的 user_header 字段
                需要注意的是:数据库中的 user_header 字段本为:user_header/???.*
                而通过序列化后,会自动变成:media/user_header/???.*
                
                例如:http://127.0.0.1:8000/media/user_header/5.jpg   
        """
        update_serializer_data['user_header'] = "127.0.0.1:8000" + serializer.data.get("user_header")
        return Response(update_serializer_data)

使用postman进行测试:

image.png 返回:

image.png

上面已经配置了文件访问,在浏览器可以自己访问127.0.0.1:8000/media/user_headers/5.jpg

image.png

5.项目优化

5.1 优化项1:设置用户默认图片

此时要更改用户的用户模型

# mdoels.py

from django.db import models
# 用户类
class User(models.Model):
    ...
    """ 此处设置用户的默认头像为 default.png """
    user_header =   models.ImageField(upload_to='user_headers/',default="user_headers/default.png")

这样就设置完成了

5.2 优化项2:图片存储优化

问题提出:

某一个用户一直在进行图片上传时,会导致原来的头像图片在Django项目的静态文件夹里没有被删除,我们需要实现一个功能,让用户上传图片文件的时候,Django会判断用户是否在数据库中的user_header中有字段,假如有的话,要删除原有的图片,将新的被上传的图片进行保存。

这样的话需要修改上传接口:

class UserHeaders(APIView):

    def put(self,request,pk):
        user = User.objects.get(id = pk)
        
        
        
        """ 新增加的的代码 """
        # 判断用户的头像,假如为非空且不为默认头像的话(也就是说用户之前已经设置头像):
        if user.user_header is not None and user.user_header != 'user_headers/default.png':
            # 访问图片文件的真实路径 即 MEDIA_ROOT根目录 + 数据库储存的路径
            """
            假如说访问的是id为2的user记录那么将会:
                settings.MEDIA_ROOT.replace('\', '/') 为:
                    D:/course_material/Study_on_Destop/test/front_end_project/end/forumend/media
                user.user_header 为:
                    user_headers/***.jpg
                那么 url就将会把他们拼接起来(中间加 / 一起拼接),为:
                    D:/course_material/Study_on_Destop/test/front_end_project/end/forumend/media/user_headers/20.jpg
            """
            url = settings.MEDIA_ROOT.replace('\', '/') + '/' + str(user.user_header)
            """ 对原有的数据库保存路径进行删除 """
            user.user_header = None
            try:
                # 调用os.remove删除指定url的文件
                os.remove(url)
            except error:
                pass
                
                
                
        # 这里进行序列化的同时就对头像进行了保存
        serializer = UserHeaderSerializer(instance=user,data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
            serializer.save()
        except ValidationError:
            return Response({"msg":serializer.errors})
        return Response({"msg":"用户头像上传成功"})