Package: django-reactive
django-reactive integratesreact-jsonschema-form(RJSF)
in Django projects.MotivationJSON typesin Postgres allow combining both relational
and non-relational approaches to storing data. That can lead to a simpler database design in the most cases.Django provides ORM support for JSON types in Postgres and other databases via theJSONField model field. Also theJSONField form fieldallows basic support of JSON in forms.
Django ORM evenallows queryingagainst the data stored
inside the JSON structures. Moreover, it is possible to improve performance of these queries usingGIN indexeswithjsonbtypesin Django, which
makes opens up a wide range of possibilities for simplifying application design, such as polymorphic collections, storing complex hierarchies in JSON, lists of related entities, etc.However, the main limitation of JSONField in Django is the lack of good support of UI for JSON structures as defining JSON objects
inside the textarea inputs is not practical for most use cases. django-reactive tries to address this problem by offering an
integration between JSONField and the awesomereact-jsonschema-form(RJSF) JavaScript library.django-reactive also uses Pythonjsonschema <https://github.com/Julian/jsonschema>library for backend validation. Such integration
can significantly reduce the amount of work needed for building custom forms for JSONField types.In most cases it only requires a JSON schema configuration for such field and optionally a UI schema
to modify some representation parameters.A basic example of this is demonstrated below:fromdjango.dbimportmodelsfromdjango_reactive.fieldsimportReactJSONSchemaFieldclassRegistration(models.Model):basic=ReactJSONSchemaField(help_text="Registration form",schema={"title":"Register now!","description":"Fill out the form to register.","type":"object","required":["firstName","lastName"],"properties":{"firstName":{"type":"string","title":"First name"},"lastName":{"type":"string","title":"Last name"},"age":{"type":"integer","title":"Age"},"bio":{"type":"string","title":"Bio"},"password":{"type":"string","title":"Password","minLength":3},"telephone":{"type":"string","title":"Telephone","minLength":10}}},ui_schema={"firstName":{"ui:autofocus":True,"ui:emptyValue":""},"age":{"ui:widget":"updown","ui:title":"Age of person","ui:description":"(earthian year)"},"bio":{"ui:widget":"textarea"},"password":{"ui:widget":"password","ui:help":"Hint: Make it strong!"},"date":{"ui:widget":"alt-datetime"},"telephone":{"ui:options":{"inputType":"tel"}}},)It will generate a form like this:Quick startInstall django-reactive:pip install django-reactiveAdd it to yourINSTALLED_APPS:INSTALLED_APPS=(...'django_reactive',...)Running the exampleBuild the docker image for the Django application inexample/:Rundocker compose up -dThis will automatically create the database, run migrations, import the default superuser, and run the Django development server onhttp://127.0.0.1:8000.Django admin exampleOpenhttp://127.0.0.1:8000/admin/and login with usernameadminand passwordtest.Go to the “Test models” admin section to see the example forms.Normal Django view exampleOpenhttp://127.0.0.1:8000/create/to create a basic form example.You will be redirected to the detail view of the created object after the form saves.Usage outside of Django adminTo use outside of the Django admin, the following are required in the template:A call to the form media property using {{ form.media }}An HTML submit input withname=”_save”.<!DOCTYPE html><html><head><title>Homepage</title></head><body>{{ form.media }}<formmethod="post">{% csrf_token %}
    {{ form }}<inputtype="submit"value="Save"name="_save"></form></body></html>Optional configurationSchema fields accept the following parameters for additional configuration:extra_css: Include additional static CSS files available in the widget.extra_js: Include additional static JavaScript files available in the widget.on_render: A python method to make dynamic schema modifications at render-time.Extra CSS and JSS files should be accessible using Django’s staticfiles configurations and passed as a list of strings.Render methods require bothschemaandui_schemaas arguments to allow dynamic schema modification when rendering the widget. An optionalinstancekeyword argument may also be used for referencing an object instance (must be set on the widget in the form). This method does not return anything.Example usageThe example below demonstrates a use-case in which the options available for a particular field may be dynamic and unavailable in the initial schema definition. These would be populated at render-time and made available in the form UI.defset_task_types(schema,ui_schema):fromtodos.modelsimportTaskTypetask_types=list(TaskType.objects.all().values_list("name",flat=True))schema["definitions"]["Task"]["properties"]["task_type"]["enum"]=task_typesui_schema["task_lists"]["items"]["tasks"]["items"]["task_type"]["ui:help"]=f"Select 1 of{len(task_types)}task types"classTodo(models.Model):"""
    A collection of task lists for a todo.
    """name=models.CharField(max_length=255)task_lists=ReactJSONSchemaField(help_text="Task lists",schema=TODO_SCHEMA,ui_schema=TODO_UI_SCHEMA,on_render=set_task_types,extra_css=["css/extra.css"],extra_js=["js/extra.js"],)Schema model form classThe form classReactJSONSchemaModelForm(subclassed from Django’sModelForm) can be used to provide the model form’s instance object to the schema field widgets:fromdjango_reactive.formsimportReactJSONSchemaModelFormclassMyModelForm(ReactJSONSchemaModelForm):...This allows theon_rendermethod set for a schema field to reference the instance like this:defupdate_the_schema(schema,ui_schema,instance=None):ifinstanceandinstance.some_condition:ui_schema["my_schema_prop"]["ui:help"]="Some extra help text"FeaturesReact, RJSF and other JS assets are bundled with the package.Integration with default Django admin theme.Backend and frontend validation.Configurable static media assets.Dynamic schema mutation in widget renders.LimitationsAdditional properties( a feature of RJSF) is not supported.To implement this behavior you can define an array schema with one property serving as a key of the object and do
transformation in the Django form.An outdated version (1.8) of RJSF is used in this project.  Not all features of RJSF 1.8 are compatible with JSON Schema 4.0. Please, refer to the documentation if any issues.Future developmentAt the moment there is no plans to add new features or support a newer version of RJSF.Probably, it is a good idea to replace RJSF with a more Django-friendly solution. It would require significant development effort though, that’s why the idea is put on back burner at the moment.