integer primary key, doc, cleanup, lint, test

This commit is contained in:
Thorsten Franzel 2019-12-14 00:00:39 +01:00
parent 1535ee2a3c
commit d8c6821563
3 changed files with 53 additions and 15 deletions

View File

@ -14,16 +14,18 @@ from django.db import models
from django.utils.encoding import force_str
from django.utils.module_loading import import_string
from rest_framework import exceptions, renderers, serializers, permissions
from rest_framework import exceptions, permissions, renderers, serializers
from rest_framework.compat import uritemplate
from rest_framework.fields import _UnvalidatedField, empty
from rest_framework.schemas.openapi_utils import (
TYPE_MAPPING, PolymorphicResponse
)
from rest_framework.settings import api_settings
from rest_framework.schemas.openapi_utils import TYPE_MAPPING, PolymorphicResponse
from .generators import BaseSchemaGenerator
from .inspectors import ViewInspector
from .utils import get_pk_description, is_list_view
AUTHENTICATION_SCHEMES = {
cls.authentication_class: cls
for cls in [import_string(cls) for cls in api_settings.SCHEMA_AUTHENTICATION_CLASSES]
@ -180,7 +182,7 @@ class AutoSchema(ViewInspector):
action_or_method = getattr(self.view, getattr(self.view, 'action', method.lower()), None)
view_doc = inspect.getdoc(self.view) or ''
action_doc = inspect.getdoc(action_or_method) or ''
return view_doc + '\n\n' + action_doc if action_doc else view_doc
return action_doc or view_doc
def get_auth(self, path, method):
""" override this for custom behaviour """
@ -262,8 +264,10 @@ class AutoSchema(ViewInspector):
elif model_field is not None and model_field.primary_key:
description = get_pk_description(model, model_field)
# TODO cover more cases
if isinstance(model_field, models.UUIDField):
# TODO are there more relevant PK base classes?
if isinstance(model_field, models.IntegerField):
schema = TYPE_MAPPING[int]
elif isinstance(model_field, models.UUIDField):
schema = TYPE_MAPPING[UUID]
parameter = {
@ -498,7 +502,7 @@ class AutoSchema(ViewInspector):
result = {
'properties': properties
}
if required and method != 'PATCH' and not nested:
if required and method != 'PATCH':
result['required'] = required
return result
@ -648,7 +652,6 @@ class AutoSchema(ViewInspector):
}
return {'200': self._get_response_for_code(path, method, schema)}
def _get_response_for_code(self, path, method, serializer_instance):
if not serializer_instance:
return {'description': 'No response body'}
@ -702,7 +705,7 @@ class AutoSchema(ViewInspector):
if name.endswith('Serializer'):
name = name[:-10]
if method == 'PATCH' and not nested:
if method == 'PATCH' and not serializer.read_only: # TODO maybe even use serializer.partial
name = 'Patched' + name
return name

View File

@ -1,8 +1,8 @@
import inspect
import warnings
from datetime import date, datetime
from decimal import Decimal
from uuid import UUID
from datetime import datetime, date
from rest_framework import authentication
from rest_framework.settings import api_settings
@ -103,6 +103,7 @@ def extend_schema(
TODO some heavy explaining
:param operation:
:param operation_id:
:param extra_parameters:
:param responses:
:param request:

View File

@ -1,14 +1,19 @@
import pytest
from django.conf.urls import url
from django.db import models
from django.test import RequestFactory, TestCase, override_settings
from django.utils.translation import gettext_lazy as _
from rest_framework import filters, generics, pagination, routers, serializers
from rest_framework import (
filters, generics, pagination, routers, serializers, viewsets
)
from rest_framework.compat import uritemplate
from rest_framework.parsers import JSONParser, MultiPartParser
from rest_framework.renderers import JSONRenderer
from rest_framework.request import Request
from rest_framework.schemas.openapi import AutoSchema, SchemaGenerator, ComponentRegistry
from rest_framework.schemas.openapi import (
AutoSchema, ComponentRegistry, SchemaGenerator
)
from . import views
@ -126,7 +131,7 @@ class TestOperationIntrospection(TestCase):
operation = inspector.get_operation(path, method)
assert operation == {
'operationId': 'example_retrieve',
'description': '\n\nA description of my GET operation.',
'description': 'A description of my GET operation.',
'parameters': [
{
'name': 'id',
@ -294,8 +299,7 @@ class TestOperationIntrospection(TestCase):
inspector = AutoSchema()
inspector.view = view
inspector.init(registry)
operation = inspector.get_operation(path, method)
inspector.get_operation(path, method)
example_schema = registry.schemas['Example']
nested_schema = registry.schemas['Nested']
@ -681,6 +685,36 @@ class TestOperationIntrospection(TestCase):
assert properties['ip']['type'] == 'string'
assert 'format' not in properties['ip']
def test_modelviewset(self):
class ExampleModel(models.Model):
text = models.TextField()
class ExampleSerializer(serializers.ModelSerializer):
class Meta:
model = ExampleModel
fields = ['id', 'text']
class ExampleViewSet(viewsets.ModelViewSet):
serializer_class = ExampleSerializer
queryset = ExampleModel.objects.none()
from django.urls import path, include
router = routers.DefaultRouter()
router.register(r'example', ExampleViewSet)
generator = SchemaGenerator(patterns=[
path(r'api/', include(router.urls))
])
generator._initialise_endpoints()
schema = generator.get_schema(request=None, public=True)
assert list(schema['paths']['/api/example/'].keys()) == ['get', 'post']
assert list(schema['paths']['/api/example/{id}/'].keys()) == ['get', 'put', 'patch', 'delete']
assert list(schema['components']['schemas'].keys()) == ['Example', 'PatchedExample']
# TODO do more checks
@pytest.mark.skipif(uritemplate is None, reason='uritemplate not installed.')
@override_settings(REST_FRAMEWORK={'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema'})