DRF NESTED FORMS
A library that parses nested json or form data to python object.
Overview
SPA's, sometimes send nested form data or json as requests encoded by some javascript libraries like json-form-data which can be difficult to handle due to the key naming conventions. This library helps to eliminate that difficulty, by parsing that nested requests into a more predictable python object that can be used by libraries like drf_writable_nested or used directly in the code.
Installation
It is available via pypi:
pip install drf_nested_forms
Usage
The utiliy class can be used directly in any part of the code.
from drf_nested_forms.utils import NestedForm
data = {
'item[attribute][0][user_type]': 'size',
'item[attribute][1][user_type]': '',
'item[verbose][]': '',
'item[variant][vendor_metric]': '[]',
'item[variant][metric_verbose_name]': 'Large',
'item[foo][baaz]': 'null',
}
options = {
'allow_blank': True,
'allow_empty': False
}
Note
.is_nested()
should be called before accessing the .data
form = NestedForm(data, **options)
form.is_nested(raise_exception=True)
The parsed result will look like below:
print(form.data)
data = {
'item': {
'attribute': [
{'user_type': 'size'},
{'user_type': ''}
],
'verbose': [''],
'variant': {
'vendor_metric': None,
'metric_verbose_name': 'Large'
},
'foo': { 'baaz': None }
}
}
DRF Integration
The parser is used with a djangorestframework view classes.
Parser classes supported:
NestedMultiPartParser
: is a default DRF multipart parser that suppport parsing nested form data.NestedJSONParser
: is a default DRF JSONParser that support parsing nested json request.
Add the parser to your django settings file
REST_FRAMEWORK = {
DEFAULT_PARSER_CLASSES = [
'drf_nested_forms.parsers.NestedMultiPartParser',
'drf_nested_forms.parsers.NestedJSONPartParser',
'rest_framework.parsers.FormParser',
]
}
To change default settings of the parsers, add OPTIONS
to NESTED_FORM_PARSER
with the new settings to your django settings file
NESTED_FORM_PARSER = {
'OPTIONS': {
'allow_empty': False,
'allow_blank': True
}
}
The parsers can also be used directly in a rest_framework
view class
from rest_framework.views import APIView
from rest_framework.parsers import FormParser
from rest_framework.response import Response
from drf_nested_forms.parsers import NestedMultiPartParser, NestedJSONParser
class TestMultiPartParserView(APIView):
parser_classes = (NestedMultiPartParser, FormParser)
def post(self, request):
return Response(data=request.data, status=200)
class TestJSONParserView(APIView):
parser_classes = (NestedJSONParser, FormParser)
def post(self, request):
return Response(data=request.data, status=200)
For example, a form or JSON data with nested params like below can be posted to any of the above drf view:
data = {
'[0][attribute]': 'true',
'[0][verbose][0]': 'bazz',
'[0][verbose][1]': 'foo',
'[0][variant][vendor_metric]': 'null',
'[0][variant][metric_verbose_name]': 'Large',
'[0][foo][baaz]': 'false',
'[1][attribute]': 'size',
'[1][verbose]': '[]',
'[1][variant][vendor_metric]': '{}',
'[1][variant][metric_verbose_name][foo][baaz][]': 'Large',
'[1][foo][baaz]': '',
'[1][logo]': '235'
}
after being parsed, the request.data
will look like this:
print(request.data)
data = [
{
'attribute': True,
'verbose': ['bazz', 'foo'],
'variant': {
'vendor_metric': None,
'metric_verbose_name': 'Large'
},
'foo': { 'baaz': False }
},
{
'attribute': 'size',
'verbose': None,
'variant': {
'vendor_metric': None,
'metric_verbose_name': { 'foo': { 'baaz': ['Large'] } }
},
'foo': { 'baaz': '' },
'logo': 235
}
]
Options
Option | Default | Description |
---|
allow_blank | True | shows empty string '' in the object |
allow_empty | False | shows empty list or dict object |
Running Tests
To run the current test suite, execute the following from the root of the project:
python runtests.py
Author
@Copyright 2021, Duke Effiom