Skip to content

Instantly share code, notes, and snippets.

@radzhome
Last active May 9, 2024 20:16
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save radzhome/d3b1586b8009ff8e1758cba6a3d92acf to your computer and use it in GitHub Desktop.
Save radzhome/d3b1586b8009ff8e1758cba6a3d92acf to your computer and use it in GitHub Desktop.
Converts json schema to django models.py
"""
Json Schema to Django Model
"""
import json
import argparse
import logging
import os
def determine_model_name(model_id=None, filename=None):
"""
Get the model name
:param model_id: str, model id
:param filename: str, filename
:return: str, model name
"""
model_name = ''
if model_id:
try:
model_name = model_id.split('/')[-1].replace('.json', '')
except Exception as e:
logging.exception("Unhandled exception {}".format(e))
if not model_name and filename:
filename = filename.strip(os.sep)
model_name = filename.split(os.sep)[-1]
model_name = model_name.split('.')[0]
return model_name.capitalize() or 'UnknownModel'
def get_required_string(key_name, required_fields, field_type='string', is_pk_field=False):
"""
Gets the required portion of model field
:param key_name:
:param required_fields:
:return: str, required model string
"""
if is_pk_field:
return 'primary_key=True'
if field_type in ('number', 'array', 'object'):
if key_name in required_fields:
return 'null=False'
return 'null=True'
else: # string, boolean
if key_name in required_fields:
return 'null=False, blank=False'
return 'null=True, blank=True'
def parse_model():
parser = argparse.ArgumentParser()
parser.add_argument('filename')
args = parser.parse_args()
filename = args.filename
with open(filename) as f:
json_model = json.load(f)
# Make sure not list, but object
if json_model['type'] != 'object':
print("Model type has to be object to convert to model, got {}".format(json_model['type']))
if 'oneOf' in json_model:
print("Optional required fields detected: {}".format(json_model['oneOf']))
# Default model string
model_str = "\nfrom djongo import models\nfrom djongo.models import json\n\n"
model_name = determine_model_name(json_model.get('id'), args.filename)
model_str += "class {}(models.Model):\n".format(model_name)
model_str += ' """Generated model from json schema"""\n'
print("Model name is {}".format(model_name))
if 'title' in json_model:
print("Title of model is {}".format(json_model['title']))
if 'description' in json_model:
print("Description of model is {}".format(json_model['description']))
required_fields = []
if 'required' in json_model:
required_fields = json_model['required']
for key_name, key_attributes in json_model['properties'].items():
if key_name.endswith('_id') and key_name != '_id':
print("WARNING: Possible ForeignKey {}".format(key_name))
# if key_attributes['type'] == 'array':
# print("ERROR: Unsupported type array, skipping for field {}".format(key_name))
if key_attributes['type'] == 'null':
print("ERROR: Unsupported type null, skipping for field {}".format(key_name))
# PK field
is_pk_field = False
if key_name in ['id', '_id']:
is_pk_field = True
# If required field
required_str = get_required_string(key_name, required_fields, key_attributes['type'], is_pk_field)
field_str = ''
# String choice field, enum
if key_attributes['type'] == 'string' and 'enum' in key_attributes:
if not key_attributes['enum']:
print("ERROR: Missing enum for enum choice field {}, skipping..".format(key_name))
continue
if len(key_attributes['enum']) == 1:
print("WARNING: enum value with single choice for field {}, choice {}."
"".format(key_name, key_attributes['enum']))
continue
# Max length find
max_length = 255
for choice in key_attributes['enum']:
if len(choice) > 255:
max_length = len(choice)
choices = tuple(set(zip(key_attributes['enum'], key_attributes['enum'])))
field_str = " {} = models.CharField(choices={}, max_length={}, " \
"default='{}', {})\n" \
"".format(key_name, choices, max_length, key_attributes['enum'][0], required_str)
# Date time field
elif key_attributes['type'] == 'string' and key_attributes.get('format') == 'date-time':
auto_now_add = False
editable = True
if key_name in ['created_on', 'modified_on']:
auto_now_add = True
editable = False
field_str = " {} = models.DateTimeField(auto_now_add={}, editable={}, {})\n" \
"".format(key_name, auto_now_add, editable, required_str)
elif key_attributes['type'] == 'string':
field_str = " {} = models.TextField({})\n".format(key_name, required_str)
elif key_attributes['type'] == 'number':
field_str = " {} = models.IntegerField({})\n".format(key_name, required_str)
elif key_attributes['type'] == 'array':
field_str = " {} = json.JSONField(default=[], {})\n".format(key_name, required_str)
elif key_attributes['type'] == 'object':
field_str = " {} = json.JSONField(default={{}}, {})\n".format(key_name, required_str)
elif key_attributes['type'] == 'boolean':
field_str = " {} = models.BooleanField(default=False, {})\n".format(key_name, required_str)
model_str += field_str
model_str += "\n class Meta:\n db_table = '{}s'\n".format(model_name.lower())
print(model_str)
if __name__ == "__main__":
parse_model()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment