Django REST Framework and JSON:API¶
The optional adapter validates JSON attributes from the same schemas as the native forms. You do not need to duplicate their properties as handwritten DRF fields. Install the integration you use:
pip install 'django-native-jsonform[drf]'
# Includes DRF through the JSON:API dependency:
pip install 'django-native-jsonform[jsonapi]'
Import adapters from django_native_jsonform.rest_framework. The main package does
not import DRF or JSON:API, so installations used only for forms stay independent.
Generate an object serializer¶
from django_native_jsonform.rest_framework import serializer_from_schema
config_schema = {
"type": "object",
"properties": {
"title": {"type": "string", "minLength": 1},
"short_title": {"type": "string"},
},
"required": ["title"],
"additionalProperties": False,
}
ConfigSerializer = serializer_from_schema(
config_schema,
name="ConfigSerializer",
json_api=True,
)
serializer = ConfigSerializer(
data={"title": "Expert Crossword", "shortTitle": "Expert"}
)
serializer.is_valid(raise_exception=True)
# With JSON_API_FORMAT_FIELD_NAMES = "camelize":
# serializer.validated_data == {"title": "Expert Crossword", "short_title": "Expert"}
# serializer.data == {"title": "Expert Crossword", "shortTitle": "Expert"}
The factory returns a reusable DRF BaseSerializer subclass. many=True supports
lists of objects. For scalar or array document roots, use JSONSchemaField instead.
It is a schema-backed serializer, not a generator of individual DRF field objects:
browsable forms and OpenAPI field enumeration do not appear automatically.
Attach a schema to a model JSONField¶
from rest_framework import serializers
from django_native_jsonform.rest_framework import JSONSchemaField
class GameConfigurationSerializer(serializers.ModelSerializer):
config = JSONSchemaField(schema=config_schema, json_api=True)
config_by_dates = JSONSchemaField(
schema={"type": "array", "items": config_schema},
json_api=True,
required=False,
)
class Meta:
model = GameConfiguration # Your application's model.
fields = ["id", "config", "config_by_dates"]
The parent model serializer persists the validated JSON values normally. Standalone
generated serializers validate and represent data; implement create() / update()
in your application if you want to call their save() method directly.
Input and output naming¶
Without json_api=True, keys match the schema exactly and no renaming takes place.
With it, the adapter recursively calls JSON:API's undo_format_field_names() on
input and format_field_names() on output. It honors
JSON_API_FORMAT_FIELD_NAMES, including camelize, dasherize, or no formatting.
Declare Python/storage keys in snake_case in the schema for this mode.
Conversion applies to every dictionary key, including arbitrary keys accepted by
additionalProperties, and dictionaries inside arrays. It does not change string
values, numbers, booleans or nulls. Use plain mode for dictionaries whose keys are
opaque identifiers that must retain their exact spelling. Colliding spellings are
rejected on both input and output instead of overwriting values. Input objects are
not mutated.
This conversion is performed by this adapter. Merely declaring a nested serializer does not make Django or JSON:API's top-level parser recursively rename JSON keys.
Validation and PATCH semantics¶
Validation reuses JSONSchemaValidator, including nested objects, arrays, nullable
values, required properties, enums, bounds, composition, conditionals and references.
Unknown properties follow additionalProperties / unevaluatedProperties; they
are not silently discarded. Values retain their JSON types: a numeric string does
not become a number. Output is also validated before formatting.
Defaults are annotations and are not inserted. JSON Schema readOnly / writeOnly
annotations do not implement API access policies: use DRF field-level options or
application logic for those policies. Business rules such as filling an empty title
from another field remain explicit application validators.
A supplied JSON attribute is a complete document, even on PATCH. The schema's
required rules still apply. The enclosing serializer's partial=True allows
omitting the entire attribute; it does not turn the JSON document into a recursive
merge patch. Applications requiring document merging must merge explicitly before
full schema validation.
Validation errors are mappings from JSON Pointers to DRF error messages, with the
schema keyword retained as the error code. For example, an invalid minimum inside
an array is reported at /rows/0/min_score. Error pointer keys use schema names.
Dynamic schemas and references¶
Pass a callable accepting the DRF context dictionary to select a schema at runtime:
ConfigSerializer = serializer_from_schema(
lambda context: context["config_schema"],
json_api=True,
)
serializer = ConfigSerializer(
data=payload,
context={"config_schema": config_schema},
)
The callable receives DRF context, not the native form's BuildContext. A wrapper
can adapt existing form schema factories. Both adapters also accept
schema_registry, schema_resources, validate_formats (default False), and
max_errors (default 100). Reference resources must be registered explicitly;
validation never fetches remote schemas automatically.
For JSON dictionaries whose keys are data (such as CSS token names), pass
preserve_key_paths=("**.colors", "**.dark_colors"). Matching subtrees retain their
keys in both directions; the property naming the subtree still follows JSON:API.
Paths use internal property names, dots, * for one segment and ** for any depth.
Schema validation still applies inside preserved subtrees.