file.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import os
  4. import uuid
  5. import hashlib
  6. import datetime
  7. from django.conf import settings
  8. from oss2.headers import OSS_OBJECT_TAGGING
  9. from apps.thirdparties import AliOSS
  10. from .exceptions import InvalidFileSize, InvalidFileName
  11. def byte_to_mega(bytes_):
  12. return bytes_ // 1024.0 // 1024.0
  13. class FileUploader(object):
  14. """
  15. 单机部署可以直接上传到本地目录
  16. 多机部署目前使用AliOssFileUploader上传到AliOSS
  17. 如果后续AliOSS成本高, 可以考虑使用minio部署文件服务
  18. """
  19. FILE_SIZE_LIMIT = 5
  20. filenameTemplate = '{filename}.{suffix}'
  21. def __init__(self, inputFile, uploadType):
  22. self.uploadType = uploadType
  23. self._inputFile = inputFile
  24. self.filename = self.filenameTemplate.format(filename = self._get_filename(), suffix = self._grab_suffix())
  25. @property
  26. def storagePath(self):
  27. return settings.MEDIA_ROOT
  28. @property
  29. def storageUrlPrefix(self):
  30. return '{}{}'.format(settings.FRONT_END_BASE_URL, settings.MEDIA_URL)
  31. @property
  32. def middlePath(self):
  33. return os.path.join(self.uploadType, datetime.datetime.now().strftime("%Y%m%d")).replace("\\", "/")
  34. def _get_filename(self):
  35. return hashlib.md5(str(uuid.uuid1())).hexdigest()
  36. def _grab_suffix(self):
  37. try:
  38. return self._inputFile.name.split('.')[1]
  39. except IndexError:
  40. raise InvalidFileName(u'文件名不合法,需要包含后缀')
  41. @property
  42. def byte_size_limit(self):
  43. return self.FILE_SIZE_LIMIT * 1024 * 1024
  44. @property
  45. def outputUrl(self):
  46. return self.storageUrlPrefix + self.filename
  47. def check(self):
  48. self._inputFile.seek(0, os.SEEK_END)
  49. size = self._inputFile.tell()
  50. if size > self.byte_size_limit:
  51. raise InvalidFileSize(u'文件过大(%sM),应该小于%dM!' % (byte_to_mega(size), self.FILE_SIZE_LIMIT),
  52. self.FILE_SIZE_LIMIT)
  53. def write(self):
  54. output_path = os.path.join(self.storagePath, self.middlePath)
  55. if not os.path.isdir(output_path):
  56. os.makedirs(output_path)
  57. output_file_path = os.path.join(output_path, self.filename)
  58. with open(output_file_path, 'wb') as destination:
  59. for chunk in self._inputFile.chunks():
  60. destination.write(chunk)
  61. def upload(self):
  62. self.check()
  63. self.write()
  64. return self.outputUrl
  65. def __repr__(self):
  66. return '<%s>with file(%s)' % (self.__class__.__name__, self.filename)
  67. class AliOssFileUploader(FileUploader):
  68. @property
  69. def storageUrlPrefix(self):
  70. return settings.MEDIA_URL
  71. @property
  72. def outputUrl(self):
  73. return settings.OSS_RESOURCE_URL + self.storageUrlPrefix + self.middlePath + '/' + self.filename
  74. def write(self):
  75. put_path = self.storageUrlPrefix[1:] + self.middlePath + '/' + self.filename
  76. AliOSS().put_object(put_path, self._inputFile.chunks())
  77. return self.outputUrl
  78. @classmethod
  79. def load(cls, url):
  80. get_path = url.replace(settings.OSS_RESOURCE_URL, '')
  81. return AliOSS().get_object(get_path[1:])
  82. class WechatSubscriptionAccountVerifyFileUploader(FileUploader):
  83. """
  84. 微信公众号自主配置时需要上传.txt文件来验证
  85. """
  86. @property
  87. def storageUrlPrefix(self):
  88. return '{}/'.format(settings.FRONT_END_BASE_URL)
  89. def _get_filename(self):
  90. return self._inputFile.name.split('.')[0]
  91. def write(self):
  92. put_path = self.filename
  93. AliOSS().put_object(put_path, self._inputFile.chunks(), headers = {
  94. 'Content-Disposition': 'attachment',
  95. OSS_OBJECT_TAGGING: 'lifecycle=7'
  96. })
  97. class SwapGroupPicFileUploader(AliOssFileUploader):
  98. """
  99. 互联互通用的充电站的图片上传
  100. """
  101. def __init__(self, inputFile, uploadType,groupId,tail):
  102. self.groupId = groupId
  103. self.tail = tail
  104. super(SwapGroupPicFileUploader, self).__init__(inputFile,uploadType)
  105. def _get_filename(self):
  106. return '%s-%s' % (self.groupId,self.tail)