Hello!
I am using Django 3.2 and python 3.9.
Django does not come with a nice api doc generator, so I made a little decorator that generates an OpenAPI spec, using pydantic models. It put the Django routes as names for the endpoints etc.
This decorator also generates the json responses, which is where my problem lies
In order to validate missing objects in a PATCH payload, I have created a sentinel object:
# A sentinel object to detect if a parameter is supplied or not.
class Missing:
pass
And the following endpoint:
@api_view(method="PATCH")
def endpoint_view(request: AuthenticatedHttpRequest, input: InputData):
update_fields: dict[str, Any] = {}
if not isinstance(input.name, Missing):
update_fields["first_name"] = input.name
And the InputData class:
class PydanticConfig:
arbitrary_types_allowed = True
@dataclass(config=PydanticConfig)
class InputData:
first_name: Union[Missing, Optional[str]] = Missing()
Now I am getting this error, while trying to generate the documentation
Traceback (most recent call last):
File "/home/circleci/project/api_utils/api_helpers.py", line 121, in generate_api_docs
schema, referenced_schemas = convert_to_schema(field_type)
File "/home/circleci/project/api_utils/api_helpers.py", line 74, in convert_to_schema
f_schema, f_definitions, f_nested_models = field_schema(model_field, model_name_map=model_name_map,
File "pydantic/schema.py", line 241, in pydantic.schema.field_schema
f_schema, f_definitions, f_nested_models = field_type_schema(
File "pydantic/schema.py", line 495, in pydantic.schema.field_type_schema
f_schema, f_definitions, f_nested_models = field_singleton_schema(
File "pydantic/schema.py", line 842, in pydantic.schema.field_singleton_schema
sub_schema, sub_definitions, sub_nested_models = model_process_schema(
File "pydantic/schema.py", line 548, in pydantic.schema.model_process_schema
m_schema, m_definitions, nested_models = model_type_schema(
File "pydantic/schema.py", line 589, in pydantic.schema.model_type_schema
f_schema, f_definitions, f_nested_models = field_schema(
File "pydantic/schema.py", line 234, in pydantic.schema.field_schema
s, schema_overrides = get_field_info_schema(field)
File "pydantic/schema.py", line 202, in pydantic.schema.get_field_info_schema
schema['default'] = encode_default(field.default)
File "pydantic/schema.py", line 899, in pydantic.schema.encode_default
return pydantic_encoder(dft)
File "pydantic/json.py", line 95, in pydantic.json.pydantic_encoder
raise TypeError(f"Object of type '{obj.__class__.__name__}' is not JSON serializable")
TypeError: Object of type 'Missing' is not JSON serializable
Now you can see, the trace says the error is thrown here:
def convert_to_schema(t: Type) -> Tuple[Dict[str, Any], Dict[str, Any]]:
"""Convert the given type to an OpenAPI v3 compatible schema.
:return The schema and a dict of schemas referenced by the schema
"""
if not hasattr(convert_to_schema, 'param_schema_counter'):
convert_to_schema.param_schema_counter = 0
convert_to_schema.param_schema_counter += 1
# Generate a Pydantic model containing only a single field named "field" of our type
# Note: pydantic doesn't seem to have any APIs for generating a schema for a single field without constructing
# a pydantic model first.
cnt = convert_to_schema.param_schema_counter # type: ignore[attr-defined]
pydantic_model: Type[BaseModel] = create_model(f"ParamSchema{cnt}", param=(t, Required))
# Extract the schema for our single field "param"
model_field = pydantic_model.__fields__['param']
# Boilerplate to get the field's schema
flat_models = get_flat_models_from_field(model_field, known_models=set())
for model in flat_models:
if lenient_issubclass(model, BaseModel):
# Alter the schema generation to add info whether the field is nullable for OpenAPI 3.0.0
# See https://github.com/samuelcolvin/pydantic/issues/1270#issuecomment-734454493
# TODO: Instead of replacing schema_extra, call the original schema_extra first, then ours
model.__config__.schema_extra = schema_extra
# TODO: Handle conflicting referenced schema names somehow if they are not actually the same schema?
model_name_map = get_model_name_map(flat_models)
f_schema, f_definitions, f_nested_models = field_schema(model_field, model_name_map=model_name_map,
ref_template=OPENAPI_REF_TEMPLATE)
# Remove title "Param" autogenerated from our field name "param"
if 'title' in f_schema:
del f_schema['title']
return f_schema, f_definitions
Any clue how I can make this sentinel object JSON serialisable?