Last active
September 10, 2024 23:06
-
-
Save radzhome/d3b1586b8009ff8e1758cba6a3d92acf to your computer and use it in GitHub Desktop.
Converts json schema to django models.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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