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进行测试:
最终图片保存成功:
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进行测试:
返回:
上面已经配置了文件访问,在浏览器可以自己访问127.0.0.1:8000/media/user_headers/5.jpg
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":"用户头像上传成功"})