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

Primary key is not an integer

Open msopacua opened this issue 2 years ago • 4 comments

My models don't use Autofield, but CUIDs, which are strings. Any foreign key in a model throws an error, that the <fieldname>_Id is not an integer. I know it isn't, but how do I make pydantic believe it?

  • I can't override the field, cause I can't exclude it, because it's not a model field
  • Simply adding the child_id to the schema and type it as string, doesn't work
  • I kind of expect this to work correctly, because the CUIDField I created extends CharField, so ninja should be able to pick up that this isn't an integer
  • I can't really figure out from the code where this is coming from:
% find $VIRTUAL_ENV/lib/python3.11/site-packages/ninja -name '*.py' -exec pcregrep -rn '(?<!operation)_id' {} + |sed -e 's,^.*-packages/ninja/,,'
openapi/schema.py:117:        op_id = operation.operation_id or self.api.get_openapi_operation_id(operation)
openapi/schema.py:118:        if op_id in self.all_operation_ids:
openapi/schema.py:120:                f'operation_id "{op_id}" is already used (func: {operation.view_func})'
openapi/schema.py:122:        self.all_operation_ids.add(op_id)
openapi/schema.py:124:            "operationId": op_id,

How do we tell Ninja that foreign keys are a string or do we need to exclude the FK name (child) and reimplement it?

msopacua avatar Nov 01 '23 16:11 msopacua

@msopacua could you provide more details - what's CUID ? is it some external field ?

could you make some reproducable example ?

vitalik avatar Nov 01 '23 16:11 vitalik

Hmm, I tried that, but in the simple case I can't trigger the error. What I'm seeing is this:

ValidationError                           Traceback (most recent call last)
Cell In[4], line 1
----> 1 MySchema.from_orm(rec)

File ~/..../python3.11/site-packages/ninja/schema.py:164, in Schema.from_orm(cls, obj)
    157 getter_dict = cls.__config__.getter_dict
    158 obj = (
    159     # DjangoGetter also needs the class so it can find resolver methods.
    160     getter_dict(obj, cls)
    161     if issubclass(getter_dict, DjangoGetter)
    162     else getter_dict(obj)
    163 )
--> 164 return super().from_orm(obj)

File ~/.../python3.11/site-packages/pydantic/main.py:579, in pydantic.main.BaseModel.from_orm()

ValidationError: 1 validation error for MySchema
child_id
  value is not a valid integer (type=type_error.integer)

If I do that with a simple Book/Author model it works as expected. I'll have to dig a bit deeper to what the issue is here. In the mean time, I can work around it with the model_exclude for the FK and reimplementing it using a resolver.

I'll close this, till I can figure out the underlying cause.

msopacua avatar Nov 01 '23 18:11 msopacua

Ok, I figured out the issue.

The problem is multi-table inheritance. When I change the model to abstract it works.

Here's a repo showing the issue with 2 tests, one failing, one succeeding.

msopacua avatar Nov 17 '23 13:11 msopacua

Added the 1.x branch to show it is also happening with 1.x.

msopacua avatar Nov 17 '23 17:11 msopacua