一:获取图片列表资源:
1:定义序列化器:
from rest_framework import serializers
from apps.goods.models import SKUImage
class ImageSerializers(serializers.ModelSerializer):
class Meta:
model = SKUImage
fields = ["id", "sku", "image"]
2:定义一个视图类:
from rest_framework.viewsets import ModelViewSet
from apps.goods.models import SKUImage
from apps.meiduo_admin.paginations import MyPage
from apps.meiduo_admin.serializers.image_serializers import ImageSerializers
class ImageView(ModelViewSet):
queryset = SKUImage.objects.all()
serializer_class = ImageSerializers
pagination_class = MyPage
3:路由:
re_path(r'^skus/images/$', ImageView.as_view({"get": "list"})),
4:测试:图片和信息获取到了。

二:新增图片可选的SKU:
1:序列化器定义:
class SKUImageSerializers(serializers.ModelSerializer):
class Meta:
model = SKU
fields =["id", "name"]
2:定义模型类:
class SKUImageView(ModelViewSet):
queryset = SKU.objects.all()
serializer_class = SKUImageSerializers
3:定义路由:
# 新增图片可选的SKU
re_path(r'^skus/simple/$', SKUImageView.as_view({"get": "list"})),
4:测试:

三:重写validate函数实现上传:
<一>: 分析:根据前端传值:传入sku的id,和image(图片–>多媒体),这是个反序列化新建资源的过程。假设能够成功。只需要路径增加:
# 图片路由:
re_path(r'^skus/images/$', ImageView.as_view({"get": "list", "post": "create"})),
我的序列化器能够完成校验的工作吗??假设前端传入的值是sku=32,经过序列化之后会变成什么呢??image图片序列化后又变成什么呢?
class ImageSerializers(serializers.ModelSerializer):
class Meta:
model = SKUImage
fields = ["id", "sku", "image"]
答案:进行validate测试一下:image变成被封装成特殊的文件对象,sku由前端传来的id类型,变成了sku对象。

特殊注意的知识点:
class SKUImage(BaseModel):
"""SKU图片"""
sku = models.ForeignKey(SKU, on_delete=models.CASCADE, verbose_name='sku')
image = models.ImageField(verbose_name='图片')
class Meta:
db_table = 'tb_sku_image'
def __str__(self):
return '%s %s' % (self.sku.name, self.id)
对于这个模型类SKUImage,如果sku这个对象被赋值成一个文件对象的话,就会自动触发文件存储后端来完成,如果sku对象被赋值成一个字符串,那么就不会触发存储后端,而是将该字符串直接存入数据库中。
class ImageSerializers(serializers.ModelSerializer):
class Meta:
model = SKUImage
fields = ["id", "sku", "image"]
def validate(self, attrs):
image_obj = attrs.get('image') # 图片文件对象
# (1)、在校验过程中,手动从文件对象中读取图片数据,上传fdfs
conn = Fdfs_client('./meiduo_mall/settings/client.conf')
res = conn.upload_by_buffer(image_obj.read())
if res is None:
raise serializers.ValidationError("fdfs上传失败!")
# (2)、再把fdfs返回的文件标示(文件id)作为有效数据中image字段的值
attrs['image'] = res['Remote file_id']
return attrs
四:自定义文件存储后端实现图片的上传:
出现的问题:像上面的图片上传,只能作用在一个视图,但是如果想要实现只要上传图片都能进行,此时就需要文件存储后端。
1:先来查看项目一中的存储后端代码:前面项目只是拼接路径返回,open和save方法没有用到,此时,模型类image字段被赋值成对象的时候,自动就会调用我的FastDFSStorage存储后端的save方法,
# 1:自定义的文件存储后端要继承django默认的存储后端Storage
class FastDFSStorage(Storage):
def _open(self, name, mode="rb" ):
# 打开django本地文件
pass
def _save(self, name, img_obj, max_length=None):
# 上传图片
pass
def url(self, name):
# 返回"http://image.meiduo.site:8888/" + 图片在数据库中存储的地址
return settings.FDFS_BASE_URL + name
save方法的参数:name:文件的名称,也就是图片保存到本地数据库中的名称(图片不存储在本地,所以用不到) img_obj: 传来的文件传来的文件对象,就是image对象被赋值后的对象,这个对象会被传递到存储后端来。注意:save返回值就是当前字段存储在mysql中的图片id。
from django.core.files.storage import Storage
from django.conf import settings
# 1:自定义的文件存储后端要继承django默认的存储后端Storage
from fdfs_client.client import Fdfs_client
from rest_framework import serializers
class FastDFSStorage(Storage):
def _open(self, name, mode="rb" ):
# 打开django本地文件
pass
def _save(self, name, image_obj, max_length=None):
# 上传图片
conn = Fdfs_client('./meiduo_mall/settings/client.conf')
res = conn.upload_by_buffer(image_obj.read())
if res is None:
raise serializers.ValidationError('上传fdfs失败!')
file_id = res['Remote file_id']
# 注意:_save方法返回值就是当前字段,存储在mysql中的文件id
return file_id
def exists(self, name):
# 功能:判断上传的文件在Django本地是否重复
# True:表示重复
# Fales:表示不重复
return False
def url(self, name):
# 返回"http://image.meiduo.site:8888/" + 图片在数据库中存储的地址
return settings.FDFS_BASE_URL + name

浙公网安备 33010602011771号