Reference resources
Temporary file, name can be obtained Memory file
demand
django receives the file uploaded by the front end and forwards it to wechat server
requsts upload file
https://2.python-requests.org//zh_CN/latest/user/advanced.html#streaming-uploads
Streaming upload
with open('massive-body') as f: requests.post('http://some.url/streamed', data=f)
Block encoding request
def gen(): yield 'hi' yield 'there' requests.post('http://some.url/chunked', data=gen())
POST multiple block encoded files
>>> url = 'http://httpbin.org/post' >>> multiple_files = [ ('images', ('foo.png', open('foo.png', 'rb'), 'image/png')), ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))] >>> r = requests.post(url, files=multiple_files) >>> r.text { ... 'files': {'images': 'data:image/png;base64,iVBORw ....'} 'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a', ... }
requests.models.py
Request code mix in
class RequestEncodingMixin(object): @staticmethod def _encode_files(files, data): """Build the body for a multipart/form-data request. Will successfully encode files when passed as a dict or a list of tuples. Order is retained if data is a list of tuples but arbitrary if parameters are supplied as a dict. The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype) # file format or 4-tuples (filename, fileobj, contentype, custom_headers). """ if (not files): raise ValueError("Files must be provided.") elif isinstance(data, basestring): raise ValueError("Data must not be a string.") new_fields = [] fields = to_key_val_list(data or {}) files = to_key_val_list(files or {}) for field, val in fields: if isinstance(val, basestring) or not hasattr(val, '__iter__'): val = [val] for v in val: if v is not None: # Don't call str() on bytestrings: in Py3 it all goes wrong. if not isinstance(v, bytes): v = str(v) new_fields.append( (field.decode('utf-8') if isinstance(field, bytes) else field, v.encode('utf-8') if isinstance(v, str) else v)) # Traverse files to get data in 2 / 3 tuple / list format for (k, v) in files: # support for explicit filename ft = None fh = None if isinstance(v, (tuple, list)): if len(v) == 2: fn, fp = v elif len(v) == 3: fn, fp, ft = v else: fn, fp, ft, fh = v else: fn = guess_filename(v) or k fp = v if isinstance(fp, (str, bytes, bytearray)): # Memory data fdata = fp elif hasattr(fp, 'read'): # File object, support read fdata = fp.read() elif fp is None: continue else: fdata = fp rf = RequestField(name=k, data=fdata, filename=fn, headers=fh) rf.make_multipart(content_type=ft) new_fields.append(rf) body, content_type = encode_multipart_formdata(new_fields) return body, content_type
Upload files in django
settings.py
# Set upload file as temporary file to avoid using memory file FILE_UPLOAD_HANDLERS = [ 'django.core.files.uploadhandler.TemporaryFileUploadHandler', ]
serializers.py upload file fields
class MaterialCreateSerializer(serializers.ModelSerializer): name = serializers.CharField( required=False, max_length=30, help_text=u'Title') content = serializers.FileField( required=True, help_text=u'Material content', validators=[ FileExtensionValidator( ['png', 'jpg', 'jpeg', 'mp4', 'mp3'] ) ] )
views.py
class XxxView(generics.GenericAPIView): permission_classes = () authentication_classes = () serializer_class = MaterialCreateSerializer def post(self, request, *args, **kwargs): """ //Service number of scenic spot in the book of songs --- parameters: - name: object pytype: serializers.MaterialCreateSerializer paramType: body """ serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): logger.error( 'WXApiView serializer err:{}'.format(serializer.errors)) return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST) data = serializer.validated_data url = data.get('url') file_data = data.get('image') if file_data.closed: fp = open(file_data.file.name, 'r') # Never execute elif isinstance(file_data, TemporaryUploadedFile): fp = file_data.file.file # file object # Use multi file upload in requests, or use but file multiple_files = [ ('file', ('file', fp, file_data.content_type)), ] resp = _post(url=url, files=multiple_files) if not fp.closed: fp.close() return resp
note
- After calling fp.read in the requests method, fp.close will not be called.
- After django orm reads the data, it will shut down actively, and fp.read - > fp.close will also be stored in oss by default.