Metadata-Version: 2.1
Name: nested-multipart-parser
Version: 1.0.0
Summary: A parser for nested data in multipart form
Home-page: https://github.com/remigermain/nested-multipart-parser
Author: Example Author
Author-email: contact@germainremi.fr
License: MIT
Project-URL: Bug Tracker, https://github.com/remigermain/nested-multipart-parser/issues
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Framework :: Django :: 2.2
Classifier: Framework :: Django :: 3.0
Classifier: Framework :: Django :: 3.1
Classifier: Framework :: Django :: 3.2
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.6
Description-Content-Type: text/markdown
License-File: LICENSE

# Nested-multipart-parser

[![build](https://github.com/remigermain/nested-multipart-parser/actions/workflows/main.yml/badge.svg)](https://github.com/remigermain/nested-multipart-parser/actions/workflows/main.yml)
[![pypi](https://img.shields.io/pypi/v/nested-multipart-parser)](https://pypi.org/project/nested-multipart-parser/)

Parser for nested data for '*multipart/form*', you can use it any python project and you have a django rest framework integration.

# Installation

```bash
pip install nested-multipart-parser
```

# How to use it

### Any python project

```python
from nested_multipart_parser import NestedParser

options = {
	"separator": "bracket"
}

def my_view():
	# options is optional
	parser = NestedParser(data, options)
	if parser.is_valid():
		validate_data = parser.validate_data
		...
	else:
		print(parser.errors)

```

### Django rest framwork

```python
from nested_multipart_parser.drf import DrfNestedParser
...

class YourViewSet(viewsets.ViewSet):
	parser_classes = (DrfNestedParser,)
```


## What is doing

The parser take the request data and transform to dictionary

exemple:

```python
# input
{
	'title': 'title',
	'date': "time",
	'simple_object[my_key]': 'title'
	'simple_object[my_list][0]': True,
	'langs[0][id]': 666,
	'langs[0][title]': 'title',
	'langs[0][description]': 'description',
	'langs[0][language]': "language",
	'langs[1][id]': 4566,
	'langs[1][title]': 'title1',
	'langs[1][description]': 'description1',
	'langs[1][language]': "language1"
}

# results are:
 {
	'title': 'title',
	'date': "time",
	'simple_object': {
		'my_key': 'title',
		'my_list': [
			True
		]
	},
	'langs': [
		{
			'id': 666,
			'title': 'title',
			'description': 'description',
			'language': 'language'
		},
		{
			'id': 4566,
			'title': 'title1',
			'description': 'description1',
			'language': 'language1'
		}
	]
}
```

## How is work

For this working perfectly you need to follow this rules:

- a first key need to be set ex: `title[0]` or `title`, in both the first key is `title`
- each sub key need to be seperate by brackets `[ ]` or dot `.` (depends of your options)
- if sub key are a full number, is converted to list *ex:* `[0]` or `[42]`
- if sub key is Not a number is converted to dictionary *ex:* `[username]` or `[article]`
- by default,the duplicate keys can't be set (see options to override that)
  ex:

```python
	data = {
		'title[0]': 'my-value'``
	}
	# output
	output = {
		'title': [
			'my-value'
		]
	}

	# invalid key
	data = {
		'title[688]': 'my-value'
	}
	# ERROR , you set a number is upper thans actual list


	# wrong format if separator is brackets (see options)
	data = {
		'title[0]]]': 'my-value',
		'title[0': 'my-value',
		'title[': 'my-value',
		'title[]': 'my-value',
		'[]': 'my-value',
	}

	data = {
		'title': 42,
		'title[object]': 42
	}
	# Error , title as alerady set by primitive value (int, boolean or string)

	# many element in list
	data = {
		'title[0]': 'my-value',
		'title[1]': 'my-second-value'
	}
	# output
	output = {
		'title': [
			'my-value',
			'my-second-value'
		]
	}

	# converted to object
	data = {
		'title[key0]': 'my-value',
		'title[key7]': 'my-second-value'
	}
	# output
	output = {
		'title': {
			'key0': 'my-value',
			'key7': 'my-second-value'
		}
	}

	# you have no limit for chained key
	data = {
		'the[0][chained][key][0][are][awesome][0][0]': 'im here !!'
	}
	# with "dot" separator in options is look like that
	data = {
		'the.0.chained.key.0.are.awesome.0.0': 'im here !!'
	}

	# the output
	output: {
		'the': [
			{
				'chained':{
					'key': [
						{
							'are': {
								'awesome':
								[
									[
										'im here !!'
									]
								]
							}
						}
					]
				}
			}
		]
	}
```

## Options

```python
{
	# the separator
	# with bracket:  article[title][authors][0]: "jhon doe"
	# with dot:      article.title.authors.0: "jhon doe"
	'separator': 'bracket' or 'dot', # default is bracket


	# raise a expections when you have duplicate keys
	# ex :
	# {
	#	"article": 42,
	#	"article[title]": 42,
	# }
	'raise_duplicate': True, # default is True

	# overide the duplicate keys, you need to set "raise_duplicate" to False
	# ex :
	# {
	#	"article": 42,
	#	"article[title]": 42,
	# }
	# the out is
	# ex :
	# {
	#	"article"{
	# 		"title": 42,
	#	}
	# }
	'assign_duplicate': False # default is False
}
```

## Options with django rest framwork

In your settings.py, add "DRF_NESTED_MULTIPART_PARSER"

```python
# settings.py
...

DRF_NESTED_MULTIPART_PARSER = {
	"separator": "bracket",
	"raise_duplicate": True,
	"assign_duplicate": False

}
```

## Javscript integration

You can use this [multipart-object](https://github.com/remigermain/multipart-object) library to easy convert object to flat nested object formated for this library

