Code Monkey home page Code Monkey logo

drf-spectacular's Introduction

drf-spectacular

build-status codecov docs pypi-version pypi-dl

Sane and flexible OpenAPI (3.0.3 & 3.1) schema generation for Django REST framework.

This project has 3 goals:
  1. Extract as much schema information from DRF as possible.
  2. Provide flexibility to make the schema usable in the real world (not only toy examples).
  3. Generate a schema that works well with the most popular client generators.

The code is a heavily modified fork of the DRF OpenAPI generator, which is/was lacking all of the below listed features.

Features

For more information visit the documentation.

License

Provided by T. Franzel. Licensed under 3-Clause BSD.

Requirements

  • Python >= 3.7
  • Django (2.2, 3.2, 4.0, 4.1, 4.2, 5.0)
  • Django REST Framework (3.10.3, 3.11, 3.12, 3.13, 3.14, 3.15)

Installation

Install using pip...

$ pip install drf-spectacular

then add drf-spectacular to installed apps in settings.py

INSTALLED_APPS = [
    # ALL YOUR APPS
    'drf_spectacular',
]

and finally register our spectacular AutoSchema with DRF.

REST_FRAMEWORK = {
    # YOUR SETTINGS
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

drf-spectacular ships with sane default settings that should work reasonably well out of the box. It is not necessary to specify any settings, but we recommend to specify at least some metadata.

SPECTACULAR_SETTINGS = {
    'TITLE': 'Your Project API',
    'DESCRIPTION': 'Your project description',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,
    # OTHER SETTINGS
}

Self-contained UI installation

Certain environments have no direct access to the internet and as such are unable to retrieve Swagger UI or Redoc from CDNs. drf-spectacular-sidecar provides these static files as a separate optional package. Usage is as follows:

$ pip install drf-spectacular[sidecar]
INSTALLED_APPS = [
    # ALL YOUR APPS
    'drf_spectacular',
    'drf_spectacular_sidecar',  # required for Django collectstatic discovery
]
SPECTACULAR_SETTINGS = {
    'SWAGGER_UI_DIST': 'SIDECAR',  # shorthand to use the sidecar instead
    'SWAGGER_UI_FAVICON_HREF': 'SIDECAR',
    'REDOC_DIST': 'SIDECAR',
    # OTHER SETTINGS
}

Release management

drf-spectacular deliberately stays below version 1.x.x to signal that every new version may potentially break you. For production we strongly recommend pinning the version and inspecting a schema diff on update.

With that said, we aim to be extremely defensive w.r.t. breaking API changes. However, we also acknowledge the fact that even slight schema changes may break your toolchain, as any existing bug may somehow also be used as a feature.

We define version increments with the following semantics. y-stream increments may contain potentially breaking changes to both API and schema. z-stream increments will never break the API and may only contain schema changes that should have a low chance of breaking you.

Take it for a spin

Generate your schema with the CLI:

$ ./manage.py spectacular --color --file schema.yml
$ docker run -p 80:8080 -e SWAGGER_JSON=/schema.yml -v ${PWD}/schema.yml:/schema.yml swaggerapi/swagger-ui

If you also want to validate your schema add the --validate flag. Or serve your schema directly from your API. We also provide convenience wrappers for swagger-ui or redoc.

from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView
urlpatterns = [
    # YOUR PATTERNS
    path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
    # Optional UI:
    path('api/schema/swagger-ui/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),
    path('api/schema/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),
]

Usage

drf-spectacular works pretty well out of the box. You might also want to set some metadata for your API. Just create a SPECTACULAR_SETTINGS dictionary in your settings.py and override the defaults. Have a look at the available settings.

The toy examples do not cover your cases? No problem, you can heavily customize how your schema will be rendered.

Customization by using @extend_schema

Most customization cases should be covered by the extend_schema decorator. We usually get pretty far with specifying OpenApiParameter and splitting request/response serializers, but the sky is the limit.

from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiExample
from drf_spectacular.types import OpenApiTypes

class AlbumViewset(viewset.ModelViewset):
    serializer_class = AlbumSerializer

    @extend_schema(
        request=AlbumCreationSerializer,
        responses={201: AlbumSerializer},
    )
    def create(self, request):
        # your non-standard behaviour
        return super().create(request)

    @extend_schema(
        # extra parameters added to the schema
        parameters=[
            OpenApiParameter(name='artist', description='Filter by artist', required=False, type=str),
            OpenApiParameter(
                name='release',
                type=OpenApiTypes.DATE,
                location=OpenApiParameter.QUERY,
                description='Filter by release date',
                examples=[
                    OpenApiExample(
                        'Example 1',
                        summary='short optional summary',
                        description='longer description',
                        value='1993-08-23'
                    ),
                    ...
                ],
            ),
        ],
        # override default docstring extraction
        description='More descriptive text',
        # provide Authentication class that deviates from the views default
        auth=None,
        # change the auto-generated operation name
        operation_id=None,
        # or even completely override what AutoSchema would generate. Provide raw Open API spec as Dict.
        operation=None,
        # attach request/response examples to the operation.
        examples=[
            OpenApiExample(
                'Example 1',
                description='longer description',
                value=...
            ),
            ...
        ],
    )
    def list(self, request):
        # your non-standard behaviour
        return super().list(request)

    @extend_schema(
        request=AlbumLikeSerializer,
        responses={204: None},
        methods=["POST"]
    )
    @extend_schema(description='Override a specific method', methods=["GET"])
    @action(detail=True, methods=['post', 'get'])
    def set_password(self, request, pk=None):
        # your action behaviour
        ...

More customization

Still not satisfied? You want more! We still got you covered. Visit customization for more information.

Testing

Install testing requirements.

$ pip install -r requirements.txt

Run with runtests.

$ ./runtests.py

You can also use the excellent tox testing tool to run the tests against all supported versions of Python and Django. Install tox globally, and then simply run:

$ tox

drf-spectacular's People

Contributors

caarmen avatar dependabot[bot] avatar diesieben07 avatar fao89 avatar federicobond avatar foarsitter avatar ftsell avatar georgy-komarov avatar glennmatthews avatar gongul avatar hoefling avatar jairhenrique avatar jalaziz avatar jayvdb avatar johnthagen avatar jorrete avatar lilisha100 avatar missial avatar ngnpope avatar nix41 avatar paulway avatar rsichnyi avatar sergei-maertens avatar spabst avatar spookylukey avatar stopmotioncuber avatar tfranzel avatar ticosax avatar v1k45 avatar viicos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

drf-spectacular's Issues

GenericSerializer schema override

I'm trying to implement a GenericSerializer to be used for all requests/responses and dynamically pass the required fields as needed.
Given three methods: X, Y and Z with different schema definitions. get_fields() indeed prints out different values. however the swagger ui takes only the first method X and place its values for all the rest of the methods Y and Z.
an attempt to generate a unique name for each method/schema did not succeed.
Screenshot - 2020-06-05T232748 791

Support for different API versions

There are different versions of API in my current project.
Like โ€‹/apiโ€‹/v{version}โ€‹/...
Is it possible to give different serializers depending on the version of api? I saw a similar implementation in the framework fastapi-versioning

Is there any possible solution to this problem? I will be very grateful for your advice

Enhancement request: Persist the mappings

The mapping of endpoint to serializer/model/whatever is incredibly useful information which can be used for other introspection type tools. It would be useful even if it was only created/updated when explicitly requested, such as a flag for the management command.

Immediate uses within drf-spectacular abound, but the most obvious and easy is to compare with reruns to detect changes in the mappings, and notify the invoker as mapping changes likely indicates the cause of some unexpected/beneficial change in generated API document.

Another use would be to augment admindocs views to provide a more detailed explanation of the data from that view. It might even be possible to inject docstrings where they are missing in the format needed by admindocs so it can perform its duty better.

The longer term concept which made me think of this is to create an API edition of https://github.com/meshy/django-schema-graph , which visually shows the openapi entities interlinked.

It would also be possible to use this data in generation without tackling the complexity of round-tripping. It would be wonderful to be able to create new mappings in the Django admin (i.e. a generated vs manual flag on the mapping data), which would allow manually mapping an APIView like djstripe's Subscription API to the appropriate serializer/model (c.f. #64).

Global security scheme not added to path.security section

When using the SECURITY setting, the defined security schemes are added at the global level.

This go's well when you do not have other authentication_classes defined. When you do have authentication_classes defined, the global defined security schemes are not added to the path.security section and thus not available for the endpoints.

My current solution is to override AuthSchema.get_auth and return None when settings.DEFAULT_AUTHENTICATION_CLASSES equals view.authentication_classes

class SettingSecureAutoSchema(AutoSchema):

    def get_auth(self):

        if api_settings.DEFAULT_AUTHENTICATION_CLASSES == self.view.authentication_classes:
            return None

        return super().get_auth()

An other solution is to add everything that is in SECURE to the path.security section.

Is this the direction you want to go? Are should we introduce a list in settings where we can add extra OpenApiAuthenticationExtension classes?

Models with custom PKs not called `id` throw errors on schema generation.

When grabbing a models "ID", should probably be using model.pk - https://docs.djangoproject.com/en/dev/ref/models/instances/#the-pk-property.
A models id field is accessable through .pk, as the models PK is always accessible there. When dealing with custom PKs, this causes drf-spectacular to fall over a AttributeError: type object 'MethodCall' has no attribute 'id' error.

For example, I have a model as follows:

class MethodCall(models.Model):
    transaction = models.OneToOneField('Transaction', primary_key=True, on_delete=models.CASCADE)
    ...

As the transaction field has primary_key=True, Django doesn't generate a .id field. However transaction is still accessable via .pk.

This is where it's an issue for me:

It may also be an issue here:

django.db.models.SlugField

I am seeing

could not resolve model field "catalogue.ProductClass.slug" due to missing mapping.either your field is custom and not based on a known subclasses or we missed something. let us know.

I havent determined which class it is, but both are derived from django.db.models.SlugField, which drf-spectacular might need a specialised handler for.

https://github.com/django-oscar/django-oscar/blob/2.0.4/src/oscar/models/fields/slugfield.py

or

https://github.com/django-oscar/django-oscar/blob/2.0.4/src/oscar/models/fields/autoslugfield.py

Enum with a different names

Actually, one more note about the EvidenceRelationship schema. I have further updated the serializer to return two different relationships in a response:

    @extend_schema_field(serializers.ChoiceField(choices=EvidenceRelationship.choices))
    def get_expert_consensus_relationship(self, obj: Evidence) -> EvidenceRelationship:
        return self.get_consensus(obj, expert=True)

    @extend_schema_field(serializers.ChoiceField(choices=EvidenceRelationship.choices))
    def get_community_consensus_relationship(self, obj: Evidence) -> EvidenceRelationship:
        return self.get_consensus(obj, expert=False)

This does work, but it's generating two separate enum types in the spec:

    ExpertConsensusRelationshipEnum:
      enum:
      - PROVES
      - SUPPORTS
      - UNRELATED
      - INCONCLUSIVE
      - DISPUTES
      - DISPROVES
      - SPLIT
      type: string
    CommunityConsensusRelationshipEnum:
      enum:
      - PROVES
      - SUPPORTS
      - UNRELATED
      - INCONCLUSIVE
      - DISPUTES
      - DISPROVES
      - SPLIT
      type: string

Is there any way to tell drf-spectacular that these are the same enum?

Originally posted by @KunstDerFuge in #68 (comment)

Support custom SessionAuthentication class

I have a class

class SessionAuthenticationWithHeader(SessionAuthentication):
    """
    This class defines authenticate_header
    which means django'll send 401 instead of 403
    """

    def authenticate_header(self, request):
        # that's non standard auth type so browser won't show default pop-up
        # see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate
        return 'session realm="api"'

When I add this class in settings

REST_FRAMEWORK = {
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'SessionAuthenticationWithHeader',
    ),

}

I get an error

Traceback (most recent call last):
  File "./manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 328, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 369, in execute
    output = self.handle(*args, **options)
  File "/opt/drf_spectacular/management/commands/spectacular.py", line 33, in handle
    schema = generator.get_schema(request=None, public=True)
  File "/opt/drf_spectacular/openapi.py", line 116, in get_schema
    'paths': self.parse(None if public else request),
  File "/opt/drf_spectacular/openapi.py", line 84, in parse
    operation = schema.get_operation(path, method, self.registry)
  File "/opt/drf_spectacular/utils.py", line 103, in get_operation
    return super().get_operation(path, method, registry)
  File "/opt/drf_spectacular/openapi.py", line 158, in get_operation
    auth = self.get_auth(path, method)
  File "/opt/drf_spectacular/utils.py", line 121, in get_auth
    return super().get_auth(path, method)
  File "/opt/drf_spectacular/openapi.py", line 184, in get_auth
    self.resolve_authentication(method, a) for a in self.view.get_authenticators()
  File "/opt/drf_spectacular/openapi.py", line 184, in <listcomp>
    self.resolve_authentication(method, a) for a in self.view.get_authenticators()
  File "/opt/drf_spectacular/openapi.py", line 789, in resolve_authentication
    raise ValueError('no auth scheme registered for {}'.format(authentication.__name__))
AttributeError: 'SessionAuthenticationWithHeader' object has no attribute '__name__'

Proposal for Required Fields

spectacular apparently is used by a few people now. i'd like to get some feedback on an idea before doing potentially invasive schema changes.

Theoretically we could make all read-only fields required. Which is imho a better representation of what DRF is actually doing. afaik DRF will always render a field even if it is null. so it is indeed required and not optional. note that this would only apply to responses and not requests.

It is an easy change, but i would like to get feedback beforehand. i don't want to break your schemas/clients. For our purposes it looks very good and the generated clients also honor it well.

i will create a pull request for you to check this out.

Object support in response

Hi

Thanks for this cool project.

I have a problem with the response scheme
I would like to see the support of the object in the answer. I will show the code, I hope you will understand what I want to see

from unittest import mock

import uuid
from django.contrib.auth.models import AbstractUser
from django.db import models
from rest_framework import routers, serializers, viewsets

from drf_spectacular.openapi import AutoSchema, SchemaGenerator
from drf_spectacular.renderers import NoAliasOpenAPIRenderer


class Album(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=100)
    genre = models.CharField(
        choices=(('POP', 'Pop'), ('ROCK', 'Rock')),
        max_length=10
    )
    year = models.IntegerField()
    released = models.BooleanField()


class Song(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    album = models.ForeignKey(Album, on_delete=models.CASCADE)

    title = models.CharField(max_length=100)
    length = models.IntegerField()


class User(AbstractUser):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)


class AuthorSerializer(serializers.ModelSerializer):
    name = models.CharField(max_length=100)

    class Meta:
        model = User
        fields = (
            'id',
            'name',
        )


class SongSerializer(serializers.ModelSerializer):
    top10 = serializers.SerializerMethodField()
    author = serializers.SerializerMethodField()

    class Meta:
        fields = ['id', 'title', 'length', 'top10', 'author']
        model = Song

    def get_top10(self) -> bool:
        return True

    def get_author(self, obj):
        return AuthorSerializer(obj.user).data


class AlbumSerializer(serializers.ModelSerializer):
    songs = SongSerializer(many=True, read_only=True)

    class Meta:
        fields = '__all__'
        model = Album


class AlbumModelViewset(viewsets.ModelViewSet):
    serializer_class = AlbumSerializer
    queryset = Album.objects.none()

    def create(self, request, *args, **kwargs):
        """
        Special documentation about creating albums

        There is even more info here
        """
        return super().create(request, *args, **kwargs)


@mock.patch('rest_framework.settings.api_settings.DEFAULT_SCHEMA_CLASS', AutoSchema)
def test_basics():
    router = routers.SimpleRouter()
    router.register('albums', AlbumModelViewset, basename="album")
    generator = SchemaGenerator(patterns=router.urls)
    schema = generator.get_schema(request=None, public=True)
    schema_yml = NoAliasOpenAPIRenderer().render(schema, renderer_context={})

    with open('test_basic.yml') as fh:
        assert schema_yml.decode() == fh.read()

When I generate the schema, then author filed is string, but should be Author object
Like this
image

Is there any way to solve this problem?

Consider the renderer class when generating the schema

Describe the bug
When generating a scheme, the renderer_classes is not used. This leads to a problem when the serializer is wrapped in an additional list. We do not use pagination in the viewset.

To Reproduce
Our example

class EnvelopedJSONRenderer(UnicodeJsonRenderer):
    def render(self, data, accepted_media_type=None, renderer_context=None):
        if renderer_context and renderer_context['response'].status_code < 400:
            if data and 'data' in data:
                # data is already enveloped (eg after pagination)
                enveloped_data = {'status': 'ok', **data}
            else:
                enveloped_data = {'status': 'ok', 'data': data}
        else:
            enveloped_data = {'status': 'error', 'error': data}
        return super().render(enveloped_data, accepted_media_type, renderer_context)

class ResponseWithStatus(serializers.Serializer):
    status = serializers.ChoiceField(choices=['ok', 'error'])


class ApiSerializer(ResponseWithStatus):
    data = NotImplemented

@memoize
def list_of(serializer_cls):
    return type(
        f'ApiList{serializer_cls.__name__}',
        (ApiSerializer,),
        {'data': serializer_cls(many=True)},
    )

@method_decorator(
    extend_schema(
        tags=['favorites'],
        responses={
            '200': list_of(FavoriteSerializer),
            '401': ResponseWithStatusAndError,
        },
        operation_id='get_favorites',
    ),
    'list',
)
class FavoritesViewSet(
    mixins.CreateModelMixin,
    mixins.DestroyModelMixin,
    mixins.ListModelMixin,
    GenericViewSet,
):
    lookup_field = 'article_uid'
    permission_classes = [IsAuthenticated]
    serializer_class = FavoriteSerializer
    renderer_classes = (EnvelopedJSONRenderer,)
    queryset = Favorite.objects.all().select_related('article')

After that we got schema:

[{
  "status": "ok",
  "data": [
    {
      "article_path": "string"
    }
  ]
}]

Expected behavior
We need to get the right scheme without wrapped list

{
  "status": "ok",
  "data": [
    {
      "article_path": "string"
    }
  ]
}

I also want to say that the drf_yasg package correctly processes this situation. Maybe you can see the implementation

0.9.5 KeyError: 'readOnly'

Commented out the fixes from https://gist.github.com/tfranzel/c29f6b79967c6d4b89b78e779e2a798f , and a different backtrace appears

Traceback (most recent call last):
  File "./manage.py", line 46, in <module>
    main()
  File "./manage.py", line 42, in main
    execute_from_command_line(sys.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 364, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/management/commands/spectacular.py", line 44, in handle
    schema = generator.get_schema(request=None, public=True)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 153, in get_schema
    paths=self.parse(request, public),
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 133, in parse
    operation = view.schema.get_operation(path, path_regex, method, self.registry)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 77, in get_operation
    operation['responses'] = self._get_response_bodies()
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 816, in _get_response_bodies
    return {'200': self._get_response_for_code(response_serializers)}
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 841, in _get_response_for_code
    component = self.resolve_serializer(serializer, 'response')
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 913, in resolve_serializer
    component.schema = self._map_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 582, in _map_serializer
    schema = self._map_basic_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 636, in _map_basic_serializer
    schema = self._map_serializer_field(field, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 419, in _map_serializer_field
    schema = self.resolve_serializer(field.child, direction).ref
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 913, in resolve_serializer
    component.schema = self._map_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 582, in _map_serializer
    schema = self._map_basic_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 636, in _map_basic_serializer
    schema = self._map_serializer_field(field, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 437, in _map_serializer_field
    del schema['readOnly']
KeyError: 'readOnly'

I'll get some better stack information shortly to identify where this and the other problem are coming from.

Use to_resource_type in PolymorphicAutoSchema

Hi!

Pls, change this:

'mapping': {c.name: c.ref['$ref'] for c in sub_components},

to:

serializer_model_mapping = {value: key for key, value in serializer.model_serializer_mapping.items()}

        return {
            'oneOf': [c.ref for c in sub_components],
            'discriminator': {
                'propertyName': serializer.resource_type_field_name,
                'mapping': {
                    serializer.to_resource_type(serializer_model_mapping[sub_components[0].object]): c.ref['$ref'] 
                    for c in subcomponents
                },
            }
        }

RelatedField serializer as int

In my project I use this serializer

class CustomSerializer(serializers.ModelSerializer):
    uid = serializers.RelatedField()
    reply_to = serializers.RelatedField()
    text = CharField()

And I would like to get the reply_to parameter in the schema as int, but I got string

How can i do this?

It seems to me that one could add typing int for reply_to parameter
For example

class CustomSerializer(serializers.ModelSerializer):
    uid = serializers.RelatedField()
    reply_to:int = serializers.RelatedField()
    text = CharField()

But it does not work

Add tags to your project

This will improve the search for the project in the github repositories, will bring more people to your project
I suggest:
openapi3
python
drf
swagger
django

Disappearing Enums

When I add another set of views which has a model that includes a status attribute, the previously defined StatusEnum is dropped and its values are moved inline to the pre-existing schemas where it was being referenced.

I can understand why that is happening, but it is a bit unusual to have components disappear when an extra unrelated API is added. These two APIs are separate - they are each only used wihin different tags. The name of the enum could be prefixed with the tag name so I had a OscarapiStatus and a SubscriptionStatus.

Support deprecated parameter

I think it should look like an extension of @extend_schema decorator
Example

@extend_schema(deprecated=True)
...

Query serializer support

In my current project i i find use query_serializer. Like this

class PublicCommentsRequest(Serializer):
    include = CharField(required=False)
    order_by = CharField(required=False)
    order_direction = ChoiceField(choices=['ASC', 'DESC'], required=False)
    start_datetime = DateTimeField(required=False)
    end_datetime = DateTimeField(required=False)
    unsafe = BooleanField(required=False)

swagger_auto_schema(
    query_serializer=PublicCommentsRequest,
    deprecated=True,
    tags=['comments'],
    operation_id='public:get_comments',
),

It looks like this
image

Could you add similar functionality?

I could use extra_parameters, but it looks complicated
Thanks

Types embedded in url paths

https://github.com/django-oscar/django-oscar-api/blob/e57b34b/oscarapi/urls.py says basket_pk has type int

However I get warnings

WARNING #130: could not derive type of path parameter "basket_pk" because model "<class 'oscar.apps.basket.models.Line'>" did contain no such field. consider annotating parameter with @extend_schema. defaulting to "string".
...
WARNING #144: could not derive type of path parameter "basket_pk" because model "<class 'oscar.apps.basket.models.LineAttribute'>" did contain no such field. consider annotating parameter with @extend_schema. defaulting to "string".

OscarHyperlinkedModelSerializer from https://github.com/django-oscar/django-oscar-api/blob/master/oscarapi/serializers/utils.py uses rest_framework.serializers.HyperlinkedModelSerializer, but the problem seems to be a customisation
extra_url_kwargs

DeprecationWarning for collections

Describe the bug
They are really going to kill it this time...

/usr/lib/python3.8/site-packages/drf_spectacular/plumbing.py:6 DeprecationWarning('Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working')

AttributeError: 'foo' object has no attribute 'required_scopes'

I am seeing a lot of occurrences of this

  File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 265, in get_auth
    auths.append(scheme.get_security_requirement(self.view))
  File "/usr/local/lib/python3.6/site-packages/drf_spectacular/contrib/authentication.py", line 32, in get_security_requirement
    return {self.name: view.required_scopes}
AttributeError: 'api_root' object has no attribute 'required_scopes'

That is the django-oscar-api, but it is so many others also.

Would it be possible for this to trigger a warning, and affected parts of the API to be discarded from the schema?

Exception: 'ManyRelatedField' object has no attribute 'Meta'

Describe the bug
(line numbers refer to master atm)

Traceback (most recent call last):
  File "./manage.py", line 14, in <module>
    main()
  File "./manage.py", line 10, in main
    execute_from_command_line(sys.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 328, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 369, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/management/commands/spectacular.py", line 44, in handle
    schema = generator.get_schema(request=None, public=True)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 152, in get_schema
    paths=self.parse(request, public),
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 132, in parse
    operation = view.schema.get_operation(path, path_regex, method, self.registry)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 76, in get_operation
    operation['responses'] = self._get_response_bodies()
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 790, in _get_response_bodies
    return {'200': self._get_response_for_code(response_serializers)}
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 815, in _get_response_for_code
    component = self.resolve_serializer(serializer, 'response')
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 887, in resolve_serializer
    component.schema = self._map_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 560, in _map_serializer
    schema = self._map_basic_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 614, in _map_basic_serializer
    schema = self._map_serializer_field(field, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 397, in _map_serializer_field
    schema = self._map_serializer_field(field.child_relation, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 409, in _map_serializer_field
    schema = self._map_model_field(field.parent.Meta.model._meta.pk, direction)
AttributeError: 'ManyRelatedField' object has no attribute 'Meta'

To Reproduce
WritableNestedModelSerializer is from https://github.com/beda-software/drf-writable-nested/blob/master/drf_writable_nested/serializers.py , but isnt related afaics.

class Foo(models.Model):
    name = models.CharField(max_length=255)


class Segment(models.Model):
    name = models.CharField(max_length=255)
    foo = models.ForeignKey(
        'Foo',
        on_delete=models.CASCADE,
        related_name='segments',
        null=True,
    )


class SegmentSerializer(WritableNestedModelSerializer):
    class Meta:
        model = Segment
        fields = ('id', 'name', 'foo')


class FooRetrieveSerializer(serializers.ModelSerializer):
    segments = serializers.PrimaryKeyRelatedField(
        read_only=True, many=True)

    class Meta:
        model = Foo
        fields = (
            'id',
            'name',
            'segments',
        )

Expected behavior
Should at least be an 'array of object', but ideally the type&schema of the object is also detected and exposed.

$ref with other fields

Hi!

Currenlty it doesn't work (the "readonly" is ignored):
image

Fix:
Change this:

return {'$ref': f'#/components/{self.type}/{self.name}'}

to:

        return {'allOf': [{'$ref': f'#/components/{self.type}/{self.name}'}]}

Result (inheritance with overriding):
image

(it doesn't look like the correct way to fix it. so, it is just example)

Type annotations on custom function-based fields

Attempting to generate a spec on a model with a custom function field gives a warning:

could not resolve field on model <class 'model_name'> with path "function_name". this is likely a custom field that does some unknown magic. maybe consider annotating the field/property? defaulting to "string".

But, I have annotated the function's return type already. Do I need to do something special in the serializer or view? Using @extend_schema with the parameter definition doesn't help.

I'm using DRF's generics.RetrieveUpdateAPIView.

(Thank you so much for the excellent efforts on this project!)

Support request parameter in ApiView

When I used swagger_auto_schema I was getting a schema with request parameters like this

from rest_framework.views import APIView


class RequestSerializer(serializers.Serializer):
    device_uuid = UUIDField()
    email = EmailField()

class MyView(views.APIView):
    renderer_classes = [JSONRenderer]

    @swagger_auto_schema(
        request_body=RequestSerializer,
        responses={'200': empty_response}, # None
    )
    def post(self, request, *args, **kwargs):
        serializer = RequestSerializer(data=request.data)
        ...
        return Response()

And in swagger it looks like this
image

When i try to use extend_schema it is not working

class MyView(views.APIView):
    renderer_classes = [EnvelopedJSONRenderer]

    @extend_schema(
        request=RequestSerializer,
        responses={200: None},
    )
    def post(self, request, *args, **kwargs):
        serializer = RequestSerializer(data=request.data)
        ...
        return Response()

I got empty body
image

How can I also do as I did before?

0.9.5: TypeError: map_serializer_field() takes 2 positional arguments but 3 were given

Upgrading from 0.9.3 ..

Traceback (most recent call last):
  File "./manage.py", line 46, in <module>
    main()
  File "./manage.py", line 42, in main
    execute_from_command_line(sys.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 364, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/management/commands/spectacular.py", line 44, in handle
    schema = generator.get_schema(request=None, public=True)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 153, in get_schema
    paths=self.parse(request, public),
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 133, in parse
    operation = view.schema.get_operation(path, path_regex, method, self.registry)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 77, in get_operation
    operation['responses'] = self._get_response_bodies()
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 816, in _get_response_bodies
    return {'200': self._get_response_for_code(response_serializers)}
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 841, in _get_response_for_code
    component = self.resolve_serializer(serializer, 'response')
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 913, in resolve_serializer
    component.schema = self._map_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 582, in _map_serializer
    schema = self._map_basic_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 636, in _map_basic_serializer
    schema = self._map_serializer_field(field, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 419, in _map_serializer_field
    schema = self.resolve_serializer(field.child, direction).ref
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 913, in resolve_serializer
    component.schema = self._map_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 582, in _map_serializer
    schema = self._map_basic_serializer(serializer, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 636, in _map_basic_serializer
    schema = self._map_serializer_field(field, direction)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/openapi.py", line 409, in _map_serializer_field
    schema = serializer_field_extension.map_serializer_field(self, direction)
TypeError: map_serializer_field() takes 2 positional arguments but 3 were given

In case this is the cause, I am using the fixes from here https://gist.github.com/tfranzel/c29f6b79967c6d4b89b78e779e2a798f

Redundant description on arrays

    InlineConcreteBundle:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        triggering_product:
          type: integer
          description: Which product should trigger this bundle?
        suggested_products:
          type: array
          items:
            type: integer
            description: Which product(s) should this bundle suggest when triggered?
          description: Which product(s) should this bundle suggest when triggered?
      required:
      - id
      - suggested_products
      - triggering_product

{format} on every endpoint, duplicate

Nice package. i'm facing the following issue:
each endpoint is duplicated in another endpoint followed by {format}. see the screenshot.
is it an issue in the package? or i'm missing something somewhere?
Screenshot - 2020-06-05T224040 889

@silk_profile

Using silk_profile from https://pypi.org/project/django-silk/ produces

WARNING #285: Unable to guess serializer for wrapped_target. This is graceful fallback handling for APIViews. Consider using GenericAPIView as view base class, if view is under your control. ignoring view for now.

The code causing this is probably my own. While I can workaround this by expanding these to use GenericAPIView, using these decorators from core drf allows for very small handlers. I only have 8 of these warnings, so it isnt a high priority for me, but worth finding a solution for as long as @api_view is still core part of drf.

@api_view(['POST'])
@silk_profile(name='Update user info')
@authentication_classes((JSONWebTokenAuthentication,))
def update_user_info(request, format=None):
    ...

This occurs with silk 3 and silk 4

git grep --context 3 wrapped_target
silk/profiling/dynamic.py-    decorator = silk_profile(name, _dynamic=True)
silk/profiling/dynamic.py-    func_name = func
silk/profiling/dynamic.py-    cls, func = _get_func(module, func_name)
silk/profiling/dynamic.py:    wrapped_target = decorator(func)
silk/profiling/dynamic.py-    if cls:
silk/profiling/dynamic.py:        setattr(cls, func_name.split('.')[-1], wrapped_target)
silk/profiling/dynamic.py-    else:
silk/profiling/dynamic.py:        setattr(module, func_name, wrapped_target)
silk/profiling/dynamic.py-
silk/profiling/dynamic.py-
silk/profiling/dynamic.py-def _get_parent_module(module):
--
silk/profiling/profiler.py-
silk/profiling/profiler.py-    def __call__(self, target):
silk/profiling/profiler.py-        if self._should_meta_profile:
silk/profiling/profiler.py:            def wrapped_target(*args, **kwargs):
silk/profiling/profiler.py-                request = DataCollector().request
silk/profiling/profiler.py-                if request:
silk/profiling/profiler.py-                    start_time = timezone.now()
--
silk/profiling/profiler.py-                    result = target(*args, **kwargs)
silk/profiling/profiler.py-                return result
silk/profiling/profiler.py-
silk/profiling/profiler.py:            return wrapped_target
silk/profiling/profiler.py-        return target
silk/profiling/profiler.py-
silk/profiling/profiler.py-
--
silk/profiling/profiler.py-
silk/profiling/profiler.py-    def __call__(self, target):
silk/profiling/profiler.py-        if self._silk_installed():
silk/profiling/profiler.py:            def wrapped_target(*args, **kwargs):
silk/profiling/profiler.py-                with silk_meta_profiler():
silk/profiling/profiler.py-                    try:
silk/profiling/profiler.py-                        func_code = target.__code__
--
silk/profiling/profiler.py-                        self._finalise_queries()
silk/profiling/profiler.py-                return result
silk/profiling/profiler.py-
silk/profiling/profiler.py:            return wrapped_target
silk/profiling/profiler.py-        else:
silk/profiling/profiler.py-            Logger.warning('Cannot execute silk_profile as silk is not installed correctly.')
silk/profiling/profiler.py-            return target

It may be that silk isnt doing the wrapping "properly" in the modern way to facilitate introspection of the underlying object, and the issue needs to be raised upstream.

django-filters emits warnings during schema generation

Describe the bug
Very low priority, but worth starting to investigate..

/usr/lib/python3.8/site-packages/django_filters/rest_framework/backends.py:147: UserWarning: <class 'foo.views.FooReportView'> is not compatible with schema generation
  warnings.warn(

If nothing else, the occurrence of these warnings is distracting, and not as informative as the warnings from drf-spectacular. Very likely they existing because of the way DRF core swagger support is/was built, and it is a useful warning for the benefit of people using the DRF core schema generation.

To Reproduce
I should be able to get a snippet if it is necessary, but it would probably be easier to replicate with a new sample meeting the criteria explained fairly easily based on the django-filters code which is getting triggered.

Expected behavior
Some of the time, but rarely it seems, drf-spectacular is doing a reasonable job despite django-filter saying there is a problem. I would need to study the generated schema more closely to understand this.

Other times, the warning from django-filters is appropriate, and drf-spectacular also emits a warning about the same thing.

Long term, the warning should be avoided because it is either redundant or incorrect. It could be avoided either by drf-spectacular pre-empting the same conditions and not invoking that code, or by filtering the warning in advance or reformatting it if it was an unexpected warning and include it in the warnings that drf-spectacular counts.

DEFAULT_METADATA_CLASS

The DRF default for DEFAULT_METADATA_CLASS is documented at https://github.com/encode/django-rest-framework/blob/master/docs/api-guide/metadata.md . The OPTIONS action allows any type of response, but I guess the content-type should be negotiated. It seems reasonable that drf-spectacular would provide an OpenAPI provider for this.

Or, perhaps find some metadata interchange mechanism with https://github.com/drf-forms/drf-schema-adapter for them to expose/maintain it as part of larger effort. If you dont like the idea of providing a DEFAULT_METADATA_CLASS here, I will create an issue there pointing back here recommending they use this as the basis of their openapi adapter.

Repeated warnings view has no attribute 'get_serializer'

This is while processing django-oscar-api. Ideally the lack of a get_serializer is noticed once per view and only one warning is emitted.

WARNING #741: Exception raised while getting serializer from CheckoutView. Hint: Is get_serializer_class() returning None or is get_queryset() not working without a request? Ignoring the view for now. (Exception: type object 'CheckoutView' has no attribute 'get_serializer')
WARNING #742: Exception raised while getting serializer from CheckoutView. Hint: Is get_serializer_class() returning None or is get_queryset() not working without a request? Ignoring the view for now. (Exception: type object 'CheckoutView' has no attribute 'get_serializer')
WARNING #743: Exception raised while getting serializer from CheckoutView. Hint: Is get_serializer_class() returning None or is get_queryset() not working without a request? Ignoring the view for now. (Exception: type object 'CheckoutView' has no attribute 'get_serializer')

Failure on SpectacularAPIView when unexpected mime type provided

I am trying to get https://github.com/dhcode/openapi-ui working, but it uses Accept: application/json, application/yaml, which causes the following backtrace as a result, and it also displays only "untagged" but will be a separate issue.

[10:46:14][ERROR] django.request log.py:log_response:228 | Internal Server Error: /schema/
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 145, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.6/site-packages/django/core/handlers/base.py", line 143, in _get_response
    response = response.render()
  File "/usr/local/lib/python3.6/site-packages/django/template/response.py", line 106, in render
    self.content = self.rendered_content
  File "/usr/local/lib/python3.6/site-packages/rest_framework/response.py", line 70, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/usr/local/src/drf-spectacular/drf_spectacular/renderers.py", line 14, in render
    return yaml.dump(data, default_flow_style=False, sort_keys=False, Dumper=Dumper).encode('utf-8')
  File "/usr/local/lib/python3.6/site-packages/yaml/__init__.py", line 290, in dump
    return dump_all([data], stream, Dumper=Dumper, **kwds)
  File "/usr/local/lib/python3.6/site-packages/yaml/__init__.py", line 278, in dump_all
    dumper.represent(data)
  File "/usr/local/lib/python3.6/site-packages/yaml/representer.py", line 27, in represent
    node = self.represent_data(data)
  File "/usr/local/lib/python3.6/site-packages/yaml/representer.py", line 48, in represent_data
    node = self.yaml_representers[data_types[0]](self, data)
  File "/usr/local/lib/python3.6/site-packages/yaml/representer.py", line 207, in represent_dict
    return self.represent_mapping('tag:yaml.org,2002:map', data)
  File "/usr/local/lib/python3.6/site-packages/yaml/representer.py", line 118, in represent_mapping
    node_value = self.represent_data(item_value)
  File "/usr/local/lib/python3.6/site-packages/yaml/representer.py", line 58, in represent_data
    node = self.yaml_representers[None](self, data)
  File "/usr/local/lib/python3.6/site-packages/yaml/representer.py", line 231, in represent_undefined
    raise RepresenterError("cannot represent an object", data)
yaml.representer.RepresenterError: ('cannot represent an object', ErrorDetail(string='Could not satisfy the request Accept header.', code='not_acceptable'))
[10:46:14][ERROR] django.server basehttp.py:log_message:154 | "GET /schema/ HTTP/1.1" 500 133266

Create Schema view for endpoints

In drf_yasg I can get the schema and put it in endpoint automatically. Could you implement the same functionality?

...
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi

...

schema_view = get_schema_view(
   openapi.Info(
      title="Snippets API",
      default_version='v1',
      description="Test description",
      terms_of_service="https://www.google.com/policies/terms/",
      contact=openapi.Contact(email="[email protected]"),
      license=openapi.License(name="BSD License"),
   ),
   public=True,
   permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
   url(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
   url(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
   url(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
   ...
]

Now I use the template and do it manually. I read the schema from the file and then use the swagger template

Improve RTD documentation

There have been a lot of feature additions recently. Some work silently in the background, other don't. Someone coming onboard now might have a hard time using some of the more advanced features.

  • Make it easier to adopt drf-spectacular
  • Make transition from drf-yasg easier. some feature basically do the same with a different name.
  • Make it easier to solve common issues.
  • Explain the usage of @extend_schema(|_fields|_serializer), Extensions and hooks and their mechanics.

Add get_schema_view() function for create Schema view for different endpoints

In drf_yasg I can create different schema views for different endpoints. Can you implement the same functionality?

from drf_yasg.views import get_schema_view
from drf_yasg import openapi

schema_view = get_schema_view(
   openapi.Info(
      title="Snippets API",
      default_version="v1",
      description="Test description",
      terms_of_service="https://www.google.com/policies/terms/",
      contact=openapi.Contact(email="[email protected]"),
      license=openapi.License(name="BSD License"),
   ),
)

urlpatterns = [
   url(r"^swagger(?P<format>\.json|\.yaml)$", schema_view.without_ui(cache_timeout=0), name="schema-json"),
]

External yaml overlay

This is a feature request.

Rather than having lots of settings and decorators, and difficulty altering the schema for installable apps, it would be nice to be able to have an external yaml file which is overlaid(merged) with the generated schema.

I would be interesting in building this if acceptable to the maintainers.

AttributeError: 'ManualSchema' object has no attribute 'get_operation'

Probably very ill-advised, I am testing https://github.com/and3rson/drfbro , and have some unrelated mods to get it semi-functional, and no settings related to it, but I am seeing the following when running dj admin command `spectacular. (i.e. not when using drfbro with spectacular)

ManualSchema is coming from django-rest-framework, rather than from drfbro itself. I have not yet checked whether the use of .schema in their view is reasonable or not; if it isnt, maybe this is just a unfortunate conflict. Ill dig more into it - just capturing the problem atm.

Traceback (most recent call last):
  File "manage.py", line 46, in <module>
    main()
  File "manage.py", line 42, in main
    execute_from_command_line(sys.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python3.8/site-packages/django/core/management/__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 328, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/lib/python3.8/site-packages/django/core/management/base.py", line 369, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/management/commands/spectacular.py", line 44, in handle
    schema = generator.get_schema(request=None, public=True)
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 153, in get_schema
    paths=self.parse(request, public),
  File "/usr/lib/python3.8/site-packages/drf_spectacular/generators.py", line 133, in parse
    operation = view.schema.get_operation(path, path_regex, method, self.registry)
AttributeError: 'ManualSchema' object has no attribute 'get_operation'

django-phonenumber-field

https://pypi.org/project/django-phonenumber-field/ 2.0.1 (unfortunately locked to that by current django-oscar & django-oscar-api & django-oscar-api-checkout):

could not resolve serializer field ModelField(help_text='In case we need to call you about your order', model_field=<phonenumber_field.modelfields.PhoneNumberField: phone_number>, required=False, validators=[<function validate_international_phonenumber>, <django.core.validators.MaxLengthValidator object>]). defaulting to "string"

The master versions should let me update to django-phonenumber-field v3, but poetry is making that difficult to upgrade with git (python-poetry/poetry#2336). Doing a fresh install to get around that.

AttributeError: 'ListSerializer' object has no attribute 'fields'

Hi,
I'm using a ListSerializer in my views and when I try to load do openapi, just raise the following exception:

...
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/views.py", line 34, in get
  public=spectacular_settings.SERVE_PUBLIC
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 107, in get_schema
  paths=self.parse(None if public else request),
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 87, in parse
  operation = view.schema.get_operation(path, method, self.registry)
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 136, in get_operation
  request_body = self._get_request_body(path, method)
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 743, in _get_request_body
  component = self.resolve_serializer(method, serializer)
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 867, in resolve_serializer
  component.schema = self._map_serializer(method, serializer)
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 605, in _map_serializer
  return self._map_basic_serializer(method, serializer)
File "/usr/local/lib/python3.6/site-packages/drf_spectacular/openapi.py", line 611, in _map_basic_serializer
  for field in serializer.fields.values():
AttributeError: 'ListSerializer' object has no attribute 'fields'

ListSerializer doesn't have fields attribute, but can be extracted from child attribute. Do you think that makes sense drf-spectacular to support this kind of serializers too?

Alpha ordering of elements in components.schemas

Describe the bug
The new alpha ordering in components.schemas is very nice, albeit I now need to find a way to verify a very large re-ordered diff, but it will be worth the pain if the new order is stable. It is a great problem to have, and im sure helpful tools abound for it.

However, I have a dejected BundleTypeEnum that has been pushed out of place to the end of the array for no apparent reason, coming from the API exposed by https://pypi.org/project/django-oscar-bundles/ . Note I am not using that API atm, so this is extremely low priority for me, and an isolated case, but it would be great to have the whole alpha ordering thing fully solved.

    ...
    BundleGroup:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        bundle_type:
          $ref: '#/components/schemas/BundleTypeEnum'
        name:
          type: string
          maxLength: 200
        headline:
          type: string
          description: CTA headline in cart display
        description:
          type: string
        image:
          type: string
          nullable: true
        triggering_parents:
          type: array
          items:
            type: integer
        suggested_parents:
          type: array
          items:
            type: integer
        concrete_bundles:
          type: array
          items:
            $ref: '#/components/schemas/InlineConcreteBundle'
        user_configurable_bundles:
          type: array
          items:
            $ref: '#/components/schemas/InlineUserConfigurableBundle'
      required:
      - concrete_bundles
      - id
      - triggering_parents
      - user_configurable_bundles
    Category:
      type: object
      properties:
        ...
    ...
    TitleEnum:
      enum:
      - Mr
      - Miss
      - Mrs
      - Ms
      - Dr
      type: string
    BundleTypeEnum:
      enum:
      - default
      type: string
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
    ...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.