django-ninja icon indicating copy to clipboard operation
django-ninja copied to clipboard

Correct usage of ForeignKey Ids in Model Schema

Open kevingill1966 opened this issue 5 months ago • 1 comments

I want to write a CRUD style API. I retrieve the model data, and save the model data. I want to do that using the schema mapped from the Django Model.

When I try it, the schema serialises using the django model attribute name. However, the validator expects the _id suffix. I am looking for the recommended way to configure the ModelSchema below to generate a JSON version with the attribute "content_type_id", instead of "content_type".

Here is an example. Execute using "python manage.py shell"

from django.contrib.auth.models import Permission
from pprint import pp
from ninja import ModelSchema, Field


class PermissionSchema(ModelSchema):
    class Meta:
        model = Permission
        fields = "__all__"


perm = Permission.objects.first()
serialiser = PermissionSchema.from_orm(perm)
d = serialiser.dict()
pp(d)

# {'id': 5, 'name': 'Can add group', 'content_type': 2, 'codename': 'add_group'}

PermissionSchema.model_validate(d)

# Traceback (most recent call last):
#   File "<console>", line 1, in <module>
#   File "/home/vscode/.local/lib/python3.11/site-packages/pydantic/main.py", line 596, in model_validate
#     return cls.__pydantic_validator__.validate_python(
#            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# pydantic_core._pydantic_core.ValidationError: 1 validation error for PermissionSchema
# content_type_id
#   Field required [type=missing, input_value=<DjangoGetter: {'id': 5, ...codename': 'add_group'}>, input_type=DjangoGetter]
#     For further information visit https://errors.pydantic.dev/2.9/v/missing

If I move the field content_type to content_type_id, it can parse

d["content_type_id"] = d.pop("content_type")

PermissionSchema.model_validate(d)
# PermissionSchema(id=5, name='Can add group', content_type=2, codename='add_group')

Note - the property name in the schema is "content_type_id", but the generated output is "content_type"

pp(PermissionSchema.schema())

# {'properties': {'id': {'anyOf': [{'type': 'integer'}, {'type': 'null'}],
#                        'title': 'ID'},
#                 'name': {'maxLength': 255, 'title': 'Name', 'type': 'string'},
#                 'content_type_id': {'title': 'Content Type', 'type': 'integer'},
#                 'codename': {'maxLength': 100,
#                              'title': 'Codename',
#                              'type': 'string'}},
#  'required': ['name', 'content_type_id', 'codename'],
#  'title': 'PermissionSchema',
#  'type': 'object'}

kevingill1966 avatar Sep 24 '24 12:09 kevingill1966