我有更好的东西!
映射器.py
import re
class Mapper:
def __init__(self):
pass
@staticmethod
def camelcase_to_underscore(camel_case):
if isinstance(camel_case, dict) or isinstance(camel_case, list):
return Mapper.dict_camelcase_to_underscore(camel_case)
else:
return re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', '_\\1', camel_case).lower().strip('_')
@staticmethod
def underscore_to_camelcase(underscore):
if isinstance(underscore, dict) or isinstance(underscore, list):
return Mapper.dict_underscore_to_camelcase(underscore)
else:
return Mapper.string_underscore_to_camelcase(underscore)
@staticmethod
def string_underscore_to_camelcase(underscore):
if '_' in underscore:
return re.sub(r'(?!^)_([a-zA-Z])', lambda m: m.group(1).upper(), underscore)
else:
return underscore
@staticmethod
def underscore_to_titlecase(underscore):
if isinstance(underscore, dict) or isinstance(underscore, list):
return Mapper.dict_underscore_to_titlecase(underscore)
else:
title_name = underscore.replace('_', ' ').title().replace(' ', '')
return title_name
@staticmethod
def titlecase_to_camelcase(titlecase):
if isinstance(titlecase, dict) or isinstance(titlecase, list):
return Mapper.dict_titlecase_to_camelcase(titlecase)
else:
if titlecase.isupper():
return titlecase.lower()
else:
val = titlecase[0].lower() + titlecase[1:]
reg = re.compile('^[A-Z]+')
front = reg.findall(titlecase)
if len(front) > 0:
if front[0].isupper() and len(front[0]) > 1:
s1 = front[0][:-1].lower()
val = s1 + titlecase[len(s1):]
if val[-2:] == "ID":
val = val[:-2] + "Id"
elif val[-3:] == "IDs":
val = val[:-3] + "Ids"
return val
@staticmethod
def dict_camelcase_to_underscore(obj):
if isinstance(obj, dict):
new_dict = {}
for key, value in obj.items():
underscore = Mapper.camelcase_to_underscore(key)
if isinstance(value, dict) or isinstance(value, list):
value = Mapper.camelcase_to_underscore(value)
new_dict[underscore] = value
return new_dict
elif isinstance(obj, list):
new_list = []
for o in obj:
new_item = {}
if isinstance(o, list):
new_item = Mapper.camelcase_to_underscore(o)
elif isinstance(o, dict):
for key, value in o.items():
underscore = Mapper.camelcase_to_underscore(key)
if isinstance(value, dict) or isinstance(value, list):
value = Mapper.camelcase_to_underscore(value)
new_item[underscore] = value
else:
new_item = o
new_list.append(new_item)
return new_list
@staticmethod
def dict_underscore_to_camelcase(obj):
if isinstance(obj, dict):
return {
Mapper.string_underscore_to_camelcase(key) : Mapper.dict_underscore_to_camelcase(value)
for key, value in obj.items()
}
if isinstance(obj, list):
return [Mapper.dict_underscore_to_camelcase(x) for x in obj]
return obj
@staticmethod
def dict_underscore_to_titlecase(obj):
if isinstance(obj, dict):
new_dict = {}
for key, value in obj.items():
titlecase = Mapper.underscore_to_titlecase(key)
if isinstance(value, dict) or isinstance(value, list):
value = Mapper.underscore_to_titlecase(value)
new_dict[titlecase] = value
return new_dict
elif isinstance(obj, list):
new_list = []
for o in obj:
new_dict = {}
for key, value in o.items():
titlecase = Mapper.underscore_to_titlecase(key)
if isinstance(value, dict) or isinstance(value, list):
value = Mapper.underscore_to_titlecase(value)
new_dict[titlecase] = value
new_list.append(new_dict)
return new_list
@staticmethod
def dict_titlecase_to_camelcase(obj):
if isinstance(obj, dict):
new_dict = {}
for key, value in obj.items():
camelcase = Mapper.titlecase_to_camelcase(key)
if isinstance(value, dict) or isinstance(value, list):
value = Mapper.titlecase_to_camelcase(value)
new_dict[camelcase] = value
return new_dict
elif isinstance(obj, list):
new_list = []
for o in obj:
new_dict = {}
if isinstance(o, dict):
for key, value in o.items():
camelcase = Mapper.titlecase_to_camelcase(key)
if isinstance(value, dict) or isinstance(value, list):
value = Mapper.titlecase_to_camelcase(value)
new_dict[camelcase] = value
new_list.append(new_dict)
else:
new_list.append(o)
return new_list
你当然必须有测试!
test_mapper.py
import random
import unittest
import uuid
from unittest.mock import MagicMock
from rest_framework_simplify.mapper import Mapper
class MapperTests(unittest.TestCase):
def test_camelcase_to_underscore_not_capitalized(self):
camel_case = 'camelCase'
underscore = 'camel_case'
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_camelcase_to_underscore_capitalized(self):
camel_case = 'CamelCase'
underscore = 'camel_case'
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_camelcase_to_underscore_array_of_numbers(self):
camel_case = {'camelCase': [1, 10]}
underscore = {'camel_case': [1, 10]}
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_camelcase_to_underscore_array_of_strings(self):
camel_case = {'camelCase': ['camelCase']}
underscore = {'camel_case': ['camelCase']}
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_camelcase_to_underscore_array_of_bools(self):
camel_case = {'camelCase': [True, False]}
underscore = {'camel_case': [True, False]}
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_camelcase_to_underscore_empty_array(self):
camel_case = {'camelCase': []}
underscore = {'camel_case': []}
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_camelcase_to_underscore_array_of_objects(self):
camel_case = {'camelCase': [{'camelCase': 1}]}
underscore = {'camel_case': [{'camel_case': 1}]}
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_camelcase_to_underscore_array_of_mixed_types(self):
int_type_value = random.randint(1, 10)
str_type_value = str(uuid.uuid4())[:4]
bool_type_value = False
obj_type_value = {'camelCase': 1}
ary_type_value = [int_type_value, obj_type_value]
underscore_mock = MagicMock(obj_type_value={'camel_case': 1}, ary_type_value=[int_type_value, {'camel_case': 1}])
camel_case = {'camelCase': [int_type_value, str_type_value, obj_type_value, ary_type_value, bool_type_value]}
underscore = {'camel_case': [int_type_value, str_type_value, underscore_mock.obj_type_value, underscore_mock.ary_type_value, bool_type_value]}
val = Mapper.camelcase_to_underscore(camel_case)
self.assertEqual(val, underscore)
def test_underscore_to_camelcase_array_of_mixed_types(self):
int_type_value = random.randint(1, 10)
str_type_value = str(uuid.uuid4())[:4]
bool_type_value = False
obj_type_value = {'camel_case': 1}
ary_type_value = [int_type_value, obj_type_value]
camel_case_mock = MagicMock(obj_type_value={'camelCase': 1}, ary_type_value=[int_type_value, {'camelCase': 1}])
underscore = {'camel_case': [int_type_value, str_type_value, obj_type_value, ary_type_value, bool_type_value]}
camel_case = {'camelCase': [int_type_value, str_type_value, camel_case_mock.obj_type_value, camel_case_mock.ary_type_value, bool_type_value]}
val = Mapper.underscore_to_camelcase(underscore)
self.assertEqual(val, camel_case)
def test_underscore_to_camelcase(self):
underscore = 'camel_case'
camel_case = 'camelCase'
val = Mapper.underscore_to_camelcase(underscore)
self.assertEqual(val, camel_case)
# I know this is horrible, but we have api's relying on this bug and we cannot fix it safely
def test_underscore_to_backwards_compatible(self):
underscore = 'address_line_1'
camel_case = 'addressLine_1'
val = Mapper.underscore_to_camelcase(underscore)
self.assertEqual(val, camel_case)
def test_underscore_to_camelcase_embedded(self):
underscore = [{'camel_case': [{'more_camel_case': 5}]}]
camel_case = [{'camelCase': [{'moreCamelCase': 5}]}]
val = Mapper.underscore_to_camelcase(underscore)
self.assertEqual(val, camel_case)
def test_title_case_full_upper(self):
upper = 'SSN'
lower = 'ssn'
val = Mapper.titlecase_to_camelcase(upper)
self.assertEqual(val, lower)
def test_title_case_mixed_bag(self):
title = 'PMSystemID'
camel = 'pmSystemId'
val = Mapper.titlecase_to_camelcase(title)
self.assertEqual(val, camel)
def test_underscore_t0_titlecase(self):
underscore = 'sum_charges'
title = 'SumCharges'
val = Mapper.underscore_to_titlecase(underscore)
self.assertEqual(val, title)
当然,您可以随时pip install rest_framework_simplify
为自己使用它!
https://github.com/Skylude/django-rest-framework-simplify