tfranzel / drf-spectacular

Sane and flexible OpenAPI 3 schema generation for Django REST framework.
https://drf-spectacular.readthedocs.io
BSD 3-Clause "New" or "Revised" License
2.32k stars 259 forks source link

PositiveIntegerField schema depends on the DB backend #962

Closed zhiltsov-max closed 1 year ago

zhiltsov-max commented 1 year ago

Describe the bug Hi, it seems that the schema generated may depend on the DB backend used. Given the following declaration:

from django.db import models
from rest_framework import serializers

class MyModel(models.Model):
    pos_int_field = models.PositiveIntegerField(null=True)

class MyModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.MyModel
        fields = ('pos_int_field', )

And 2 DB backends for development (Sqlite3) and production (Postgres):

# development
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        ...
    },
}

# production
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        ...
    }
}

We have 2 different schemes generated:

# with sqlite3
    MyModelRequest:
      type: object
      properties:
        pos_int_field:
          type: integer
          nullable: true

# with postgres
    MyModelRequest:
      type: object
      properties:
        pos_int_field:
          type: integer
          maximum: 2147483647 # extra field
          minimum: 0 # extra field
          nullable: true

How to reproduce

Out environment is:

Django==3.2.18
djangorestframework==3.12.4
drf-spectacular==0.22.1

Expected behavior Probably, the API schema fields should not depend on the server DB backend used, and the schema generated should be the same in both cases.

tfranzel commented 1 year ago

Hi @zhiltsov-max, that is interesting. We do not directly depend on the DB backend itself. However, we do use DRF's mechanics by which they generate a ModelSerializer.

Behind the scenes, DRF is building a serializer for you. We merely report all the properties we find on that serializer. It looks like DRF sets min/max validators on that auto-generated field. On our end, we do not manually add those min/max properties! Unfortunately, behavior seems to differ between different backends.

Not sure if we could even do anything about it. It is generally complicated for us to differentiate what a user added and what DRF auto-populated for you.

And technically it might even be the right thing. If you have no other limiting factors (model/serializer field params or validators), the DB decides what it allows as baseline.

tfranzel commented 1 year ago

It may very well be that your test environment with sqlite3 will accept a different range of values than your postgres production environment, if you fully leave serializer generation up to DRF.

On first glance, I can't really see what size sqlite+django will choose for the int: https://www.sqlite.org/datatype3.html