Encode multipart POST data from a dictionary of form values. The key will be used as the form data name; the value will be transmitted as content. If the value is a file, the contents of the file will be sent as an application/octet-stream; otherwise, str(value) will be sent.
(boundary, data)
| 276 | |
| 277 | |
| 278 | def encode_multipart(boundary, data): |
| 279 | """ |
| 280 | Encode multipart POST data from a dictionary of form values. |
| 281 | |
| 282 | The key will be used as the form data name; the value will be transmitted |
| 283 | as content. If the value is a file, the contents of the file will be sent |
| 284 | as an application/octet-stream; otherwise, str(value) will be sent. |
| 285 | """ |
| 286 | lines = [] |
| 287 | |
| 288 | def to_bytes(s): |
| 289 | return force_bytes(s, settings.DEFAULT_CHARSET) |
| 290 | |
| 291 | # Not by any means perfect, but good enough for our purposes. |
| 292 | def is_file(thing): |
| 293 | return hasattr(thing, "read") and callable(thing.read) |
| 294 | |
| 295 | # Each bit of the multipart form data could be either a form value or a |
| 296 | # file, or a *list* of form values and/or files. Remember that HTTP field |
| 297 | # names can be duplicated! |
| 298 | for key, value in data.items(): |
| 299 | if value is None: |
| 300 | raise TypeError( |
| 301 | "Cannot encode None for key '%s' as POST data. Did you mean " |
| 302 | "to pass an empty string or omit the value?" % key |
| 303 | ) |
| 304 | elif is_file(value): |
| 305 | lines.extend(encode_file(boundary, key, value)) |
| 306 | elif not isinstance(value, str) and isinstance(value, Iterable): |
| 307 | for item in value: |
| 308 | if is_file(item): |
| 309 | lines.extend(encode_file(boundary, key, item)) |
| 310 | else: |
| 311 | lines.extend( |
| 312 | to_bytes(val) |
| 313 | for val in [ |
| 314 | "--%s" % boundary, |
| 315 | 'Content-Disposition: form-data; name="%s"' % key, |
| 316 | "", |
| 317 | item, |
| 318 | ] |
| 319 | ) |
| 320 | else: |
| 321 | lines.extend( |
| 322 | to_bytes(val) |
| 323 | for val in [ |
| 324 | "--%s" % boundary, |
| 325 | 'Content-Disposition: form-data; name="%s"' % key, |
| 326 | "", |
| 327 | value, |
| 328 | ] |
| 329 | ) |
| 330 | |
| 331 | lines.extend( |
| 332 | [ |
| 333 | to_bytes("--%s--" % boundary), |
| 334 | b"", |
| 335 | ] |