def update(self, request, *args, **kwargs): # 获取当前要修改的图片对象 instance = self.get_object() # 接收 name = request.data.get('name') first_letter = request.data.get('first_letter') logo = request.data.get('logo') # 验证 if not all(['name', 'first_letter']): return Response({'detail:'数据不完整'}, status=400) # 处理 # 1.fdfs:删除旧图片,上传新图片 if logo: # 如果用户上传图片则修改 image_client = Fdfs_client(settings.FDFS_CLIENT_CONF) # 删除===>instance.logo.name===>获取图片的名称字符串 image_client.delete_file(instance.logo.name) # 上传 data = image_client.upload_by_buffer(logo.read()) instance.logo = data.get("Remote file_id") instance.name = name instance.first_letter = first_letter else: instance.name = name instance.first_letter = first_letter # 2.保存对象 instance.save() # 响应 serializer = self.get_serializer(instance) return Response(serializer.data, status=201)
def update(self, request, *args, **kwargs): instence = ModelViewSet.get_object(self) sku_ID = request.data.get('sku') image = request.data.get('image') if not all([sku_ID]): return Response({'detail':'数据不完整'},status=400) if image: image_client = Fdfs_client(settings.FASTDFS_PATH) image_client.delete_file(instence.image.name) data = image_client.upload_by_buffer(image.read()) instence.image = data.get('Remote file_id') instence.sku_id = sku_ID instence.save() serializer = self.get_serializer(instence) return Response(serializer.data,status=200)
def update(self, request, *args, **kwargs): # 获取当前要修改的图片对象 instance = self.get_object() # 接收 sku_id = request.data.get('sku') image = request.data.get('image') # 验证 if not all([sku_id]): return Response({'detail:'数据不完整'}, status=400) # 处理 # 1.fdfs:删除旧图片,上传新图片 if image: # 如果用户上传图片则修改 image_client = Fdfs_client(settings.FDFS_CLIENT_CONF) # 删除===>instance.image.name===>获取图片的名称字符串 image_client.delete_file(instance.image.name) # 上传 data = image_client.upload_by_buffer(image.read()) instance.image = data.get("Remote file_id") # 2.修改对象 instance.sku_id = sku_id instance.save() # 响应 serializer = self.get_serializer(instance) return Response(serializer.data, status=201)
def destroy(self, request, *args, **kwargs): instance = self.get_object() sku = instance.sku image_url = instance.image.name try: # 删除文件 client = Fdfs_client(settings.FDFS_CLIENT_CONF) client.delete_file(image_url) except: pass with transaction.atomic(): sid = transaction.savepoint() try: instance.delete() # 如果删除的图片,是sku的默认图片 if sku.default_image.name == image_url: # 查询sku的所有图片 images = sku.images.all() if images: # 将第一个作为默认图片 sku.default_image = images[0].image else: sku.default_image = None sku.save() except Exception as e: transaction.savepoint_rollback(sid) raise serializers.ValidationError('图片删除失败') # raise e else: transaction.savepoint_commit(sid) generate_detail_html.delay(sku.id) return Response(status=204)
def destroy(self, request, *args, **kwargs): instance = self.get_object() client = Fdfs_client(settings.FDFS_CLIENT_CONF) try: client.delete_file(instance.logo.name) except Exception as e: pass instance.delete() return Response(status=HTTP_201_CREATED)
def delete(self, name): """ name:文件id :param name: :return: """ client = Fdfs_client(self.client_conf) # 删除FDFS中存储的图片 client.delete_file(name)
def destroy(self, request, *args, **kwargs): instance = self.get_object() logo_old = instance.logo.name client = Fdfs_client(settings.FDFS_CLIENT_CONF) try: client.delete_file(logo_old) except: pass response = super().destroy(request, *args, **kwargs) return response
def destroy(self, request, *args, **kwargs): # 查询当前对象 instance = self.get_object() image_client = Fdfs_client(settings.FDFS_CLIENT_CONF) # 删除===>instance.logo.name===>获取图片的名称字符串 image_client.delete_file(instance.image.name) # 删除图片 instance.delete() # 响应 return Response(status=204)
def destroy(self, request, *args, **kwargs): instance = self.get_object() image_client = Fdfs_client(settings.FASTDFS_PATH) if instance.image.name : image_client.delete_file(instance.image.name) else: pass instance.delete() return Response(status=200)
def update(self, request, *args, **kwargs): # 1.接收参数 """ 请求体的参数:<QueryDict: {'sku': ['2'], 'image': [<InMemoryUploadedFile: gouzi.png (image/png)>]}> kwargs: {'pk': '51'} """ sku_id = request.data.get('sku') data = request.FILES.get('image') img_id = kwargs.get('pk') # 2.校验参数 try: sku = SKU.objects.get(pk=sku_id) except SKU.DoesNotExist: return Response({'message': 'sku is not found'}, status=status.HTTP_404_NOT_FOUND) try: pic = SKUImage.objects.get(pk=img_id) except SKUImage.DoesNotExist: return Response({'message': 'image is not found'}, status=status.HTTP_404_NOT_FOUND) # 3.修改图片 client = Fdfs_client(settings.FASTDFS_PATH) # 3.1 先删除 fsatdfs 老图片 client.delete_file(pic.image.name) # 3.2 再上传 新图片 result = client.upload_by_buffer(data.read()) # 4.判断 修改完毕的状态 if result['Status'] != 'Upload successed.': return Response({'messsage': '图片上传失败!'}, status=status.HTTP_403_FORBIDDEN) # 5.改SKUImage数据 upload_img_url = result['Remote file_id'] pic.image = upload_img_url pic.save() # 6.页面静态化 get_detail_html.delay(sku_id) return Response({ "id": pic.id, "sku": sku.id, "image": pic.image.url }, status=201)
def delete(self, name): '''删除文件''' # 获取storage client 对象 client = Fdfs_client(self.fdfs_client_conf) # 删除文件 print('delete:', name) ret = client.delete_file(name) print(ret)
def delete(self, name): cli = Fdfs_client(self.conf_path) if not isinstance(name, bytes): name = name.encode() try: result = cli.delete_file(name) except FDFSError as e: raise errors.Error(errmsg=f'从FastDFS删除文件{name}失败:') from e logger.debug(f'FastDFS delete: {result}') if result[0] != 'Delete file successed.': raise errors.Error(errmsg=f'FastDFS删除文件{name}失败: {result}')
def destroy(self, request, *args, **kwargs): # 1.接收参数 img_id = kwargs['pk'] # 2.校验 try: pic = SKUImage.objects.get(pk=img_id) except SKUImage.DoesNotExist: return Response({'message': 'image not found'}, status=404) # 3.fastDFS删除图片 client = Fdfs_client(settings.FASTDFS_PATH) client.delete_file(pic.image.name) # 4.删除image数据库数据 pic.delete() # 5.返回响应 return Response(status=204)
def update(self, request, *args, **kwargs): instance = self.get_object() # fast = FastDFSStorage() # url = fast.save(name=None, content=request.FILES.get('image')) client = Fdfs_client(settings.FDFS_CLIENT_CONF) try: client.delete_file(instance.image.name) except Exception as e: pass result = client.upload_by_buffer(request.FILES.get('image').read()) if result.get('Status') != 'Upload successed.': raise Exception('上传文件到FDFS系统失败') url = result.get('Remote file_id') instance.image = url instance.save() return Response( { "id": instance.id, "sku": instance.sku_id, "image": instance.image.url }, status=HTTP_201_CREATED)
def delete(self, name): """name:要删除文件的id""" client = Fdfs_client(self.client_conf) print(name) # 删除FDFS中存储的图片 try: res = client.delete_file(name) except Exception as e: print(e) else: print('删除成功')
def update(self, request, *args, **kwargs): instance = self.get_object() name = request.data.get('name') first_letter = request.data.get('first_letter') logo = request.data.get('logo') logo_old = instance.logo.name if not all([name, first_letter, logo]): raise serializers.ValidationError('数据不全') client = Fdfs_client(settings.FDFS_CLIENT_CONF) ret = client.upload_appender_by_buffer(logo.read()) if ret.get('Status') != 'Upload successed.': return Response('图片上传失败') image_url = ret.get('Remote file_id') # 保存信息 instance.name = name instance.first_letter = first_letter instance.logo = image_url instance.save() # 删除旧的商标 client.delete_file(logo_old) serializer = self.get_serializer(instance) return Response(serializer.data, status=201)
def update(self, request, *args, **kwargs): instance = self.get_object() client = Fdfs_client(settings.FDFS_CLIENT_CONF) try: client.delete_file(instance.logo.name) except Exception as e: pass result = client.upload_by_buffer(request.FILES.get('logo').read()) if result.get('Status') != 'Upload successed.': raise Exception('上传文件到FDFS系统失败') url = result.get('Remote file_id') instance.logo = url instance.name = request.data.get('name') instance.first_letter = request.data.get('first_letter') instance.save() return Response({ "id": instance.id, "name": instance.name, "logo": instance.logo.url, "first_letter": instance.first_letter }, status=HTTP_201_CREATED )
class Fdfs(): def __init__(self, client_file): self.client = Fdfs_client(client_file) def upload(self, upload_file): try: ret_upload = self.client.upload_by_filename(upload_file) file_id = ret_upload['Remote file_id'].replace('\\', '/') return file_id except Exception as e: return None def uploadbyBuffer(self, file, suffix): try: ret_upload = self.client.upload_by_buffer(file, suffix) file_id = ret_upload['Remote file_id'].replace('\\', '/') return file_id except Exception as e: print(e) return None def downloadbyBuffer(self, file_id): try: ret_download = self.client.download_to_buffer(file_id) ret_content = ret_download['Content'] return ret_content except Exception as e: return None def download(self, download_file, file_id): try: ret_download = self.client.download_to_file(download_file, file_id) ret_content = ret_download['Content'] return ret_content except Exception as e: return None def delete(self, file_id): try: ret_delete = self.client.delete_file(file_id) return ret_delete except Exception as e: return None
def update(self, request, *args, **kwargs): # 获取修改的对象 instance = self.get_object() # 接收 sku_id sku_id = request.data.get('sku') # 接收图片数据 image_file = request.data.get('image') # 校验参数 if not sku_id: raise serializers.ValidationError('数据不完整') try: sku = SKU.objects.get(id=sku_id) except: raise serializers.ValidationError('修改的商品不存在') # 获取修改对象的image_url image_url_instance = instance.image.name client = Fdfs_client(settings.FDFS_CLIENT_CONF) # 删除旧的image, 将其放在事务中执行 # client.delete_file(image_url_instance) # 上传新的图片 ret = client.upload_appender_by_buffer(image_file.read()) if ret.get('Status') != 'Upload successed.': return Response('图片上传失败') # 获取新的url image_url = ret.get('Remote file_id') with transaction.atomic(): save_point = transaction.savepoint() try: # 判断是否修改商品 if instance.sku_id == int(sku_id): # 只是修改了图片 # 判断修改的是否是商品的默认图片, 如果是就要修改sku表 if sku.default_image == image_url_instance: sku.default_image = image_url sku.save() else: # 商品及图片都修改 # 获取被修改的sku sku_old = SKU.objects.get(id=instance.sku_id) # 判断修改的图片是不是被修改商品的默认图片 if sku_old.default_image == image_url_instance: # 判断 sku_old 是否还有图片, 要先排除要被修改的图片 images = sku_old.images.exclude( image=image_url_instance) if images: # 有就将查询集中的第一张图片设置为默认图片 sku_old.default_image = images[0].image else: # 没有就设置为空 sku_old.default_image = None sku_old.save() # 判断要修改的商品有没有默认图片, 及有没有图片 if not sku.default_image or not sku.images.count(): # 如果没有, 就将其设置为默认图片 sku.default_image = image_url sku.save() # 修改图片表 instance.image = image_url instance.sku_id = sku_id instance.save() except: transaction.savepoint_rollback(save_point) raise serializers.ValidationError('修改失败') else: client.delete_file(image_url_instance) transaction.savepoint_commit(save_point) serializer = self.get_serializer(instance) return Response(serializer.data)
class FDFSStorage(Storage): """ 自定义文件图片储存系统为FDFS, 仅针对django的后台管理,前端上传要重新写,原理还是这个 """ def __init__(self): """ 初始化参数 :param settings.BASE_URL: 图片储存的基类路径 :param settings.FDFS_CLIENT_CONF:客户端的配置文件的路径 """ self.base_url = settings.BASE_URL self.client = Fdfs_client(settings.FDFS_CLIENT_CONF) def _open(self, name, mode): # 前端传过来的已经是二进制文件了,因此可以直接pass不写 pass def _save(self, name, content): """重写_save方法为FDFS上传 upload_by_buffer方法 ->upload_by_buffer(self, filebuffer, file_ext_name=None, meta_dict=None): 通过file_ext_name设置文件后缀名,(meta_dict设置其他参数信息[猜测可以]) @meta_dict: dictionary e.g.:{ 'ext_name' : 'jpg', 'file_size' : '10240B', 'width' : '160px', 'hight' : '80px' } """ file_type = name.split('.')[-1] if '.' in name else None # 传个两次,不成功就算了 for i in range(2): # 调用连接对象的二进制上传文件方法 result = self.client.upload_by_buffer(content.read(), file_type) # 判断上传图片是否成功,失败主动报错 if result['Status'] == 'Upload successed.': break else: raise Exception('fdfs客户端连接对象上传图片失败') # 成功则返回文件id self.result = result return self.result['Remote file_id'] def url(self, name): """返回图片的fdfs完整路径""" return self.base_url + name def exists(self, name): """让django认为每次上传的文件都是新文件""" return False def size(self, name): """返回图片大小""" return self.result.get('Uploaded size') def delete(self, name): """删除文件, 这个name,就是image字段存在数据库里的值""" assert name, "The name argument is not allowed to be empty." self.client.delete_file(name) def listdir(self, path): pass def path(self, name): return self.url(name) def get_accessed_time(self, name): return time.time() def get_created_time(self, name): return time.time() def get_modified_time(self, name): return time.time()
class FastDfsStorage(Storage): """操作文件通过file_id""" def __init__(self, base_url=None, client_conf=None): """ 初始化 :param base_url:构造图片上传的基本url,包括域名,已经搭配nginx :param client_conf:FastDfs客户端的配置字典 """ if base_url is None: base_url = FDFS_URL self.base_url = base_url if client_conf is None: client_conf = FDFS_CLIENT_CONF self.client_conf = client_conf self.client = Fdfs_client(get_tracker_conf(self.client_conf)) def _open(self, name, mode='rb'): """返回封装后的文件对象""" return File(open(self.path(name), mode)) def open(self, name, mode='rb'): """ 从FastDfs中取出文件 :param name: 文件名 :param mode: 打开的模式 :return: """ return self._open(name, mode) def _save(self, name, content): """ 存储文件到FastDfs上 :param name: 文件名(无卵用) :param content: 打开的file对象 :return: """ filebuffer = content.read() # 读取二进制内容 is_save, ret_upload = self.upload(filebuffer) return ret_upload.get('Remote file_id').decode() if is_save else None def save(self, name, content, max_length=None): """ Save new content to the file specified by name. The content should be a proper File object or any Python file-like object, ready to be read from the beginning. """ # Get the proper name for the file, as it will actually be saved. # 要不要name无所谓,只是为了尽量不改底层源码 if name is None: name = content.name if not hasattr(content, 'chunks'): content = File(content, name) name = self.get_available_name(name, max_length=max_length) # 截取固定大小的文件名长度 return self._save(name, content) def update(self, filebuffer, remote_file_id): """ 修改文件内容 :param local_path: 本地文件名 :param remote_file_id: fastdfs中的file_id @return: dictionary { 'Status' : 'Modify successed.', 'Storage IP' : storage_ip } """ try: remote_file_id = bytes(remote_file_id.encode("utf-8")) # 旧的file_id ret_update = self.client.modify_by_buffer(filebuffer, remote_file_id) if ret_update.get("Status") != 'Modify successed.': raise Exception return True, ret_update except Exception as e: common_logger.info(e) return None, "文件更新失败" def upload(self, filebuffer, meta_dict=None): """ 保存文件时回调的函数 保存在FastDfs中 通过client来操作 :param name: 文件名 :param filebuffer: 文件内容(二进制) :param meta_dict: dictionary e.g.:{ 'ext_name' : 'jpg', 'file_size' : '10240B', 'width' : '160px', 'hight' : '80px' } @return dict { 'Group name' : group_name, 'Remote file_id' : remote_file_id, 'Status' : 'Upload successed.', 'Local file name' : '', 'Uploaded size' : upload_size, 'Storage IP' : storage_ip } if success else None """ try: ret_upload = self.client.upload_by_buffer(filebuffer) if ret_upload.get("Status") != "Upload successed.": raise Exception return True, ret_upload # file_name为bytes类型,只能返回str类型,不然会报错 except Exception as e: return False, None def url(self, name): """ 返回文件的完整URL路径给前端 :param name: 数据库中保存的文件名 :return: 完整的URL """ return self.base_url + '/' + name def exists(self, name): """ 判断文件是否存在,FastDFS可以自行解决文件的重名问题 所以此处返回False,告诉Django上传的都是新文件 :param name: 文件名 :return: False """ return False def download_to_file(self, local_path, remote_file_id): """ 从FastDfs分布式文件系统进行下载文件,保存成文件格式 :param local_path: 本地保存文件路径 :param remote_file_id: 上传到FastDfs文件系统中自动生成的文件路径即文件id, :return True/False, dict { 'Remote file_id' : remote_file_id, 'Content' : local_filename, 'Download size' : downloaded_size, 'Storage IP' : storage_ip } """ try: ret_download = self.client.download_to_file(local_path, remote_file_id) return True, ret_download except Exception as e: return False, None def download_to_buffer(self, remote_file_id, offset=0, down_bytes=0): """ 通过文件名从FastDfs上下载文件,存储为buffer格式 :param local_filename: 本地文件名,一般存于数据库 :param remote_file_id: 远程文件id :param offset: 文件数据起始偏移量 :param down_bytes: 需要下载的文件大小 :return:return True/False, dict { 'Remote file_id' : remote_file_id, 'Content' : file_buffer, 'Download size' : downloaded_size, 'Storage IP' : storage_ip } """ try: ret_download = self.client.download_to_buffer(remote_file_id, offset, down_bytes) return True, ret_download except Exception as e: return False, None def modify_by_buffer(self, filebuffer, appender_fileid, offset=0): """ 通过buffer修改文件内容 :param filebuffer:文件buffer :param appender_fileid:远程文件id :param offset:起始偏移量 :return:True/False, dictionary { 'Status' : 'Modify successed.', 'Storage IP' : storage_ip } """ try: ret_modify = self.client.modify_by_buffer(filebuffer, appender_fileid, offset) return True, ret_modify except Exception as e: return False, None def delete(self, remote_file_id): """ 从FastDfs分布式文件系统中将文件删除 :param remote_file_id: 上传到FastDfs文件系统中自动生成的文件路径即文件id @return True/False, tuple ('Delete file successed.', remote_file_id, storage_ip) """ try: ret_delete = self.client.delete_file(remote_file_id) return True, ret_delete except Exception as e: return False, None
client = Fdfs_client('client.conf') # 上传文件 # ret = client.upload_by_filename('/home/python/Desktop/iphone.jpg') """ { 'Group name': 'group1', 'Storage IP': '192.168.136.130', 'Local file name': '/home/python/Desktop/iphone.jpg', 'Status': 'Upload successed.', 'Uploaded size': '6.00KB', 'Remote file_id': 'group1/M00/00/02/wKiIgl09S5SAM9cSAAAaSQ5Z0Cc893.jpg' } """ # 修改文件 # ret = client.modify_by_file('/home/python/Desktop/huawei.jpg', 'group1/M00/00/02/wKiIgl09S5SAM9cSAAAaSQ5Z0Cc893.jpg') """ 包错误 使用先删除在上传的方法 """ # 删除 ret = client.delete_file('group1/M00/00/02/wKiIgl09S5SAM9cSAAAaSQ5Z0Cc893.jpg') """ ( 'Delete file successed.', 'group1/M00/00/02/wKiIgl09S5SAM9cSAAAaSQ5Z0Cc893.jpg', '192.168.136.130' ) """ print(ret)
#!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 3/7/19 9:39 AM # @Author : Lijunjie # @Site : # @File : upload_file # @Software: PyCharm import os from fdfs_client.client import Fdfs_client dirname = "/mnt/hgfs/CS/培训/14天天生鲜项目/dailyfresh/static/images" client = Fdfs_client("/etc/fdfs/client.conf") for main_dir, subdir, file_name_list in os.walk(dirname): for file_name in file_name_list: file = os.path.join(main_dir, file_name) with open(file, 'rb') as f_obj: res = client.upload_by_buffer(f_obj.read()) print(file) print(res["Remote file_id"]) client.delete_file(res['Remote file_id'])