python request file upload_python requests 上传文件

参考

需求

django 收取到前端上传的文件后转发到微信服务器

requsts 上传文件

流式上传

with open('massive-body') as f:

requests.post('http://some.url/streamed', data=f)

块编码请求

def gen():

yield 'hi'

yield 'there'

requests.post('http://some.url/chunked', data=gen())

POST 多个分块编码的文件

>>> 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

请求编码混入

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) # 文件格式

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))

# 遍历files获取2/3元组/list格式的数据.

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)): # 内存数据

fdata = fp

elif hasattr(fp, 'read'): # 文件对象, 支持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

django 中上传文件

settings.py

# 设置上传文件为临时文件,避免使用内存文件

FILE_UPLOAD_HANDLERS = [

'django.core.files.uploadhandler.TemporaryFileUploadHandler',

]

serializers.py 上传文件字段

class MaterialCreateSerializer(serializers.ModelSerializer):

name = serializers.CharField(

required=False, max_length=30, help_text=u'标题')

content = serializers.FileField(

required=True, help_text=u'材料内容',

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):

"""

诗经里景区服务号上传摇一摇功能图片素材

---

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') # 从不执行

elif isinstance(file_data, TemporaryUploadedFile):

fp = file_data.file.file # file对象

# 使用requets中的多文件上传, 也可使用但文件

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

requests 方法中调用fp.read后,不会调用fp.close

django orm 读取数据后,会主动关闭, 默认存储oss 中也会fp.read->fp.close。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值